레슨 11 / 12·6개 토픽
에러 처리와 Set/Map
try / catch / finally
try 블록에서 에러가 발생하면 catch로 잡아서 처리합니다. finally는 에러 발생 여부와 관계없이 항상 실행됩니다. 에러를 적절히 처리하면 프로그램이 비정상 종료되지 않습니다.
javascript
// 기본 try / catch / finally
try {
const data = JSON.parse("잘못된 JSON");
} catch (error) {
console.log(error.name); // "SyntaxError"
console.log(error.message); // "Unexpected token ..."
} finally {
console.log("항상 실행됩니다");
}
// 에러 던지기
function divide(a, b) {
if (b === 0) {
throw new Error("0으로 나눌 수 없습니다");
}
return a / b;
}
try {
console.log(divide(10, 0));
} catch (e) {
console.log(e.message); // "0으로 나눌 수 없습니다"
}내장 에러 타입
- •
TypeError— 값의 타입이 잘못되었을 때 (null.property,"str"()) - •
ReferenceError— 정의되지 않은 변수를 참조할 때 - •
SyntaxError— 코드 문법이 잘못되었을 때 (JSON.parse 실패 등) - •
RangeError— 값이 허용 범위를 벗어날 때 (new Array(-1)) - •
URIError— URI 인코딩/디코딩 오류 - •
EvalError— eval() 관련 오류 (현대 JS에서는 거의 발생하지 않음)
javascript
// 에러 타입별 분기 처리
function processInput(input) {
try {
const data = JSON.parse(input);
return data.value.toUpperCase();
} catch (e) {
if (e instanceof SyntaxError) {
console.log("JSON 파싱 실패:", e.message);
} else if (e instanceof TypeError) {
console.log("속성 접근 실패:", e.message);
} else {
throw e; // 알 수 없는 에러는 다시 던지기
}
}
}
processInput("유효하지 않은 JSON"); // "JSON 파싱 실패: ..."
processInput('{"noValue": 1}'); // "속성 접근 실패: ..."커스텀 에러 클래스
javascript
// 커스텀 에러 만들기
class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = "ValidationError";
this.field = field;
}
}
class NotFoundError extends Error {
constructor(resource) {
super(resource + "을(를) 찾을 수 없습니다");
this.name = "NotFoundError";
this.resource = resource;
}
}
// 사용 예시
function validateAge(age) {
if (typeof age !== "number") {
throw new ValidationError("age", "숫자여야 합니다");
}
if (age < 0 || age > 150) {
throw new ValidationError("age", "0~150 범위여야 합니다");
}
return true;
}
try {
validateAge("스물다섯");
} catch (e) {
if (e instanceof ValidationError) {
console.log(e.field + ": " + e.message);
// "age: 숫자여야 합니다"
}
}Set 심화
Set은 중복 없는 값의 컬렉션입니다. 값의 존재 확인(has)이 배열의 includes보다 훨씬 빠르며(O(1) vs O(n)), 집합 연산에 유용합니다.
javascript
// Set 기본 메서드
const tags = new Set();
tags.add("javascript");
tags.add("web");
tags.add("javascript"); // 중복 무시
console.log(tags.size); // 2
console.log(tags.has("web")); // true
tags.delete("web");
console.log(tags.size); // 1
// 배열 → Set → 배열 (중복 제거)
const numbers = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(numbers)]; // [1, 2, 3, 4]
// Set 순회
const fruits = new Set(["사과", "바나나", "체리"]);
for (const fruit of fruits) {
console.log(fruit);
}
fruits.forEach(fruit => console.log(fruit));
// 집합 연산
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
// 합집합
const union = new Set([...setA, ...setB]);
// {1, 2, 3, 4, 5, 6}
// 교집합
const intersection = new Set([...setA].filter(x => setB.has(x)));
// {3, 4}
// 차집합
const difference = new Set([...setA].filter(x => !setB.has(x)));
// {1, 2}Map 심화
Map은 키-값 쌍의 컬렉션으로, 일반 객체와 달리 어떤 타입이든 키로 사용 가능합니다. 삽입 순서가 보장되고, size로 바로 크기를 확인할 수 있습니다.
javascript
// Map 기본 메서드
const userRoles = new Map();
userRoles.set("김철수", "admin");
userRoles.set("이영희", "editor");
userRoles.set("박민수", "viewer");
console.log(userRoles.get("김철수")); // "admin"
console.log(userRoles.has("이영희")); // true
console.log(userRoles.size); // 3
userRoles.delete("박민수");
// Map 순회
for (const [name, role] of userRoles) {
console.log(name + ": " + role);
}
// 객체를 키로 사용 (일반 객체로는 불가능)
const elementCounts = new Map();
const div = document.createElement("div");
const span = document.createElement("span");
elementCounts.set(div, 5);
elementCounts.set(span, 3);
console.log(elementCounts.get(div)); // 5
// Map vs Object 비교
const obj = {};
obj["key"] = "value";
console.log(Object.keys(obj).length); // size 직접 확인 불가
const map = new Map();
map.set("key", "value");
console.log(map.size); // 1 — 바로 확인 가능WeakMap과 WeakSet
WeakMap과 WeakSet은 키(WeakMap) 또는 값(WeakSet)으로 객체만 허용하며, 다른 곳에서 참조가 없어지면 가비지 컬렉션됩니다. 메모리 누수 방지에 유용합니다.
javascript
// WeakMap — DOM 요소에 데이터 연결 (메모리 누수 방지)
const metadata = new WeakMap();
function trackElement(element, info) {
metadata.set(element, info);
}
let btn = document.createElement("button");
trackElement(btn, { clicks: 0, created: Date.now() });
console.log(metadata.get(btn)); // { clicks: 0, created: ... }
btn = null; // 참조 제거 → WeakMap에서도 자동 정리됨
// WeakSet — 객체 방문 여부 추적
const visited = new WeakSet();
function processNode(node) {
if (visited.has(node)) {
return; // 이미 방문한 노드 스킵
}
visited.add(node);
console.log("처리:", node.id);
}
const nodeA = { id: "A" };
const nodeB = { id: "B" };
processNode(nodeA); // "처리: A"
processNode(nodeA); // (스킵)
processNode(nodeB); // "처리: B"💡
WeakMap/WeakSet은 순회(iteration)가 불가능하고 size 속성이 없습니다. 이는 가비지 컬렉션 시점을 예측할 수 없기 때문입니다. 캐시, DOM 메타데이터, 순환 참조 방지 등에 활용하세요.