자바스크립트로 조금 더 안정적인 프로그램을 만들기 위해서는 에러를 다루는 방법을 알아두는 것이 중요하다. 자바스크립트는 코드가 실행되는 도중에 에러가 발생하면 자동으로 그 에러에 대한 정보가 담긴 에러 객체를 생성한다.
에러 메시지는 크게 에러 객체의 이름과 조금 더 구체적인 내용이 담긴 메시지로 나뉘어져 있다. 그래서 에러 객체는 공통적으로 에러 객체의 이름을 담고 있는 name이라는 프로퍼티와 구체적인 에러 내용을 담고 있는 message라는 프로퍼티가 존재한다.
일반적으로 우리가 자주 볼 수 있는 에러 객체는 크게 세 가지 정도로 요약할 수 있다.
Reference Error 레퍼런스 에러
존재하지 않는 변수나 함수를 호출할 때 발생하는 에러
Type Error 타입 에러
문자열이 담긴 변수를 함수처럼 사용해서 잘못된 방식으로 자료형을 다루려고 하면 발생하는 에러
Syntax Error 신택스 에러
문법에 맞지 않는 코드를 작성하게 되면 발생하는 에러. 코드 자체에서 발생하는 부분이 있다면 아예 코드를 실행하기도 전에 에러를 발생 시킨다.
에러 객체에 이름과 내용이라는 형식을 맞추면 우리가 직접 에러 객체를 만들어 낼 수도 있다.
console.log('시작!');
const error = new TypeError('타입 에러가 발생했습니다.');
console.log(error.name);
console.log(error.message);
console.log('끝!');
앞쪽에 new라는 키워드를 붙이고 에러 객체에 이름을 함수처럼 호출해서 아규먼트로 우리가 원하는 메시지를 전달해주면 새로운 에러객체를 만들 수 있다. 이렇게 하면 name에는 TypeError가 그리고 message 프로퍼티에는 "타입 에러가 발생했습니다." 라는 문자열이 저장된 에러 객체가 만들어진다. 이렇게 에러 객체를 만들어낸 것이다.
console.log('시작!');
const error = new TypeError('타입 에러가 발생했습니다.');
throw error;
console.log(error.name);
console.log(error.message);
console.log('끝!');
throw 키워드 다음에 에러 객체를 작성해주게 되면 코드를 실행하면 우리가 작성한 에러 객체가 발생하게 되고, 에러가 발생한 시점 이후의 코드는 동작하지 않는다.
try {
//코드
} catch (error) {
//에러가 발생했을 때 동작할 코드
}
에러가 발생했을 때 프로그램이 바로 종료되는 게 아니라 catch문 안에 작성한 코드가 동작하게 된다. 이를 응용해서
try {
console.log('에러 전');
const codeit = '코드잇';
console.log(codeit)
codeit = 'codeit';
const language = 'JavaScript';
console.log(language);
} catch (error) {
console.log('에러 후');
}
에러가 발생한 시점 이후에는 코드가 실행되지 않는다.
try...catch문을 사용하지 않았을 때는 에러가 발생하면 에러 객체가 생성되면서 콘솔에 붉은 색으로 에러 메시지가 출력됐었다. try문 안에서도 에러가 발생하면 똑같이 에러 객체가 생성된다. 콘솔에 바로 출력되는 게 아니라 error라는 파라미터에 전달된다.
catch (error) {
console.log('에러 후');
}
error 파라미터는 err 아니면 e 등의 이름으로 붙여준다. 그리고 log 메소드가 아니라 error 메소드를 사용하면 실제 에러처럼 출력할 수 있다.
function printMembers(members) {
for (const member of members) {
console.log(member);
}
}
const teamA = ['상해', '혜진', '지혜', '혜선'];
printMembers(teamA);
const codeit = { name: 'codeit' };
printMembers(codeit);
const teamB = ['영훈', '재훈', '종훈', '정훈'];
printMembers(teamB);
11번 줄을 보면 아규먼트로 배열이 아닌 객체 값을 사용하고 있는데, 객체는 for...of 문을 사용할 수 없기 때문에 이 3번 줄에서 에러가 발생하게 된다. 여기서 문제는 이 에러로 인해서 그 아래 코드는 실행되지 않고 프로그램이 그대로 멈춰버린다. 이런 상황에서 함수 내부에서 try...catch문을 활용하게 되면
function printMembers(members) {
try {
for (const member of members) {
console.log(member);
}
} catch (err) {
console.error(err);
alert(`${err.name}가 발생했습니다. 콘솔창을 확인해 주세요.`);
}
}
const teamA = ['상해', '혜진', '지혜', '혜선'];
printMembers(teamA);
const codeit = { name: 'codeit' };
printMembers(codeit);
const teamB = ['영훈', '재훈', '종훈', '정훈'];
printMembers(teamB);
이 try문 안에서 에러가 발생하더라도 catch문에서 에러 객체를 다루기 때문에 프로그램을 멈추지 않고 그 이후의 코드들을 안전하게 실행시킬 수 있게 된다.
한 가지 주의해야 할 점은 try...catch문도 결국 각각의 코드블록으로 이루어진 것이다.
try {
const title = 'Codeit';
} catch (err) {
console.error(err);
}
이 코드를 보면 title 변수를 try문 안에서 선언을 했다. 그런데 try문도 결국은 중괄호로 감싸진 코드 블록이기 때문에 try문에서 선언한 이 title 변수는 이렇게 catch문 안에서도 사용할 수 없고
try {
const title = 'Codeit';
} catch (err) {
console.error(err);
console.log(title);
}
try문 바깥에서도 사용할 수가 없다.
try {
const title = 'Codeit';
} catch (err) {
console.error(err);
}
console.log(title);
그래서 let이나 const처럼 블록 스코프를 갖는 변수를 활용할 때 각 코드 블록 안에서의 스코프를 잘 생각해야 된다.
참고로 이 try...catch문은 실행이 가능한 코드 내에서의 에러를 다룬다. SyntaxError는 코드를 아예 실행조차 하지 않는다. 일단은 실행이 가능한 코드에서 발생한 에러를 예외, Exception이라고 부른다. 실행 가능한 코드에서 발생한 에러를 다루는 과정을 가리켜서 예외 처리, Exception Handling이라는 용어로 부른다.
try {
// 실행할 코드
} catch (err) {
// 에러가 발상했을 때 실행할 코드
} finally {
// 항상 실행할 코드
}
try문에서 에러가 발생하지 않는다면 try문의 코드가 모두 실행된 다음에,
try문에서 에러가 발생한다면 catch문의 코드가 모두 실행된 다음 실행할 코드를 finally문에 작성하면 된다.
for (const member of members) {
console.log(member);
}
}
try {
printMembers('영훈', '윤수', '동욱');
} catch (err) {
alert('에러가 발생했습니다!');
console.log(err);
} finally {
const end = new Date();
const msg = `코드 실행을 완료한 시각은 ${end.toLacaleString()}입니다.`;
console.log(msg);
}
다시 말해 try문에서 어떤 코드를 실행할 때 에러 여부와 상관 없이 항상 실행할 코드를 작성하는 것이다.
finally 문에서 에러가 발생할 경우에는 다시 그 위에 있는 catch문으로 넘어가진 않는다. 만약 finally 문에서도 에러 처리가 필요한 경우 아래 처럼 try...catch문을 중첩해서 활용하는 방법이 있다.
try {
try {
// 실행할 코드
} catch (err) {
// 항상 실행할 코드
}
} catch (err) {
// finally문에서 에러가 발생했을 때 실행할 코드
}