지금까지 에러를 처리할 때 예상 가능한 에러를 try..catch 로 처리하였습니다. 그런데 또 다른 예기치 않은 에러가 try {..} 블록 안에서 발생 할 수도 있습니다. 정의되지 않은 변수 사용 등의 프로그래밍 에러가 발생할 가능성은 항상 있습니다.
let json = '{ "age": 30 }'; // 불완전한 데이터
try {
user = JSON.parse(json); // <-- user 앞에 let 을 붙이는 걸 잊음.
// ...
} catch (err) {
alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined
// (실제로 JSON Error 가 아닙니다.)
}
에러는 어떤 상황에서도 발생할 수 있습니다. 위에선 ‘불완전한 데이터’를 다루려는 목적으로 try..catch
를 썼습니다. catch 는 원래 try 블록에서 발생한 모든 에러를 잡으려는 목적으로 만들어졌습니다.
그런데 위 예시에서 catch 는 예상치 못한 에러를 잡아내 주긴 했지만, 에러 종류와 관계없이 “JSON Error” 메시지를 보여줍니다. 이렇게 에러 종류와 관계없이 동일한 방식으로 에러를 처리하는 것은 디버깅
을 어렵게 만들기 때문에 좋지 않습니다.
이런 문제를 피하고자 ‘다시 던지기(rethrowing)
’ 기술을 사용합니다. 규칙은 간단합니다.
catch는 알고 있는 에러만 처리하고 나머지는 ‘다시 던져야’ 합니다.
보통 에러 타입을 instanceof
명령어로 체크합니다.
try {
user = { /*...*/ };
} catch (err) {
if(err instanceof ReferenceError) {
alert('ReferenceError'); // 정의되지 않은 변수에 접근하면 'ReferenceError' 발생
}
}
*err.name
프로퍼티로 에러 클래스 이름을 알 수도 있습니다. 기본형 에러는 모두 err.name
프로퍼티를 가집니다. 또는 err.constructor.name
을 사용할 수도 있습니다.*
에러를 다시 던져서 catch 블록에선 SyntaxError
만 처리되도록 해보겠습니다.
let json = '{ "age": 30 }'; // 불완전한 데이터
try {
let user = JSON.parse(json);
if(!user.name) {
throw new SyntaxError("불완전한 데이터: 이름 없음");
}
test(); // 예상치 못한 에러
alert(user.name);
} catch(err) {
if(err instanceof SyntaxError) {
alert("JSON Error: " + err.message);
} else {
throw err; // 에러 다시 던지기 (*)
}
}