(23) Modern JavaScript - try...catch 문

반응형

다음과 같이 자바스크립트 에서는 에러가 발생하는 순간

프로그램이 종료되고 그 이후 코드가 동작하지 않는다.

console.log("Start");

const title = "섭이";
console.log(title);

title = "섭이";

const language = "JavaScript";
console.log(language);

console.log("End");

코드를 실행한 결과, 7번 줄에서 const 키워드로 선언한 변수에

새로운 값을 재할당 하려고 했기 때문에 TypeError가 발생했다.

그래서 중간에 멈춰버리는 바람에 그 아래 language 변수와 

"End" 문자열은 출력되지 않았다는 것을 확인할 수 있다.

 

그래서 자바스크립트로 프로그래밍을 할 때 이 에러를 다루는 방법을 알아야

조금 더 안정적인 프로그램을 만들 수 있다.

그래서 그런 에러를 다루는 방법 중 하나 인 "try...catch"문을 사용한다.


try...catch 문

이름 그대로 try와 catch 키워드를 사용하며 문법은 다음과 같다.

// try catch문
try {
  // 코드
} catch (error) {
  // 에러가 발생했을 때 동작할 코드
}

두 개의 코드 블록으로 구성되어 있는 try...catch는

먼저 try 블록에서 동작 시킬 코드를 작성하고

try 블록 안의 코드가 실행되다가 에러가 발생하게 되면

그때 동작할 코드를 catch 블록 안에 작성한다.

실행해보면 에러가 발생했을 때 바로 프로그램이 종료되는 것이 아니라

catch문 안에서 작성한 코드가 동작하게 된다.

한번 직접 코드를 작성해보자


try {
  console.log("Start");

  const title = "섭이";
  console.log(title);

  title = "섭이";

  const language = "JavaScript";
  console.log(language);
} catch (error) {
  console.log("End");
}

코드를 풀이 해보자면

try문 안의 코드가 동작하다가 8번 줄에서 재할당 하려는 값에 에러가 발생한다.

그런데 에러가 발생하고 나서 프로그램이 종료되는 것이 아니라 catch문 안의 코드가 동작한다.

그래서 에러가 아니라 catch문 안에 있는 "End" 문자열이 출력된다.


그런데 8번 줄에서 에러가 발생했기 때문에 

try 블록 내에서 에러가 발생한 시점 이후의 코드는 실행되지 않아서

 "language" 변수에 들어있는 "JavaScript"는 동작하지 않은 것이다.

 

만약 에러가 발생한 시점을 주석 처리하고 실행해보면 

try {
  console.log("Start");

  const title = "섭이";
  console.log(title);

  // title = "섭이";

  const language = "JavaScript";
  console.log(language);
} catch (error) {
  console.log("End");

 try 문에있는 나머지 코드들이 실행되고 

에러가 발생한 부분은 주석 처리 했기 때문에 catch문의 동작 조건에 맞지 않아

"End" 문자열은 출력되지 않는다.


한가지만 더 살펴보자면

catch 키워드 오른쪽에 있는 "error" 파라미터는약속된 값이 아니라

아무렇게나 이름을 붙여도 상관없다. (보통은 "error", "err" 두 가지를 많이 쓰는 편)

catch (error) {}

 

그리고 try...catch문을 사용하지 않았을 때 에러가 발생하면

에러 객체가 생성되면서 콘솔에 에러 메시지가 출력된다고 했을 때,

try문 안에서 에러가 발생하면 똑같이 에러 객체가 생성되고

콘솔에 바로 출력되는 것이 아니라 "error" 파라미터에 전달되는 것이다.

 

그래서 catch문에서 에러 객체와 name, message 프로퍼티를 출력해보면

다음과 같이 "error" 파라미터에 전달된 에러 객체가 출력될 것이다.

try {
  console.log("Start");

  const title = "섭이";
  console.log(title);

  title = "섭이";

  const language = "JavaScript";
  console.log(language);
} catch (error) {
  console.log("End");
  console.log(error);
  console.log(error.name);
  console.log(error.message);
}

 

또한 좀 더 에러 같은 에러(?)를 출력하고 싶다면

"console.log"메소드가 아니라 "console.error" 로 작성하면 된다.

try {
  console.log("Start");

  const title = "섭이";
  console.log(title);

  title = "섭이";

  const language = "JavaScript";
  console.log(language);
} catch (error) {
  console.log("End");
  // console.log(error);
  console.error(error);

  console.log(error.name);
  console.log(error.message);
}

 

여기까지가 try...catch문의 기본적인 동작 원리이다.


try...catch 문 활용하기

아래 members라는 파라미터에 아규먼트로 배열이 전달되는 것을 의도하여

각 배열의 요소를 콘솔에 출력하는 함수를 만들었다.

// try catch문 활용
function printMembers(members) {
  for (const member of members) {
    console.log(member);
  }
}

const oldTeam = ["넌적혈구", "스기따라", "행섭", "양천", "데셔"];
printMembers(oldTeam);

const Team = { name: "메롱팟" };
printMembers(Team);

const youngTeam = ["찌듕", "힝카인"];
printMembers(youngTeam);

그런데 12번줄에 있는 Team을 보면 아규먼트로 배열이 아닌 객체 값을 사용하고 있다. 

객체는 for...of문을 사용할 수 없기 때문에 3번 줄에서 에러가 발생한다.

이 에러로 인해 코드는 실행되지 않고 프로그램이 멈춰버렸기에

함수 내부에서 try catch문을 활용해 "youngTeam"을 호출해보자.


이런 상황에서 함수 내부에 try catch문을 활용하게 되면 

try문 안에서 에러가 발생하더라도 catch문에서 에러 객체를 다루기 때문에

프로그램을 멈추지 않고 그 이후의 코드들을 안전하게 실행시킬 수 있게 된다.

// try catch문 활용
function printMembers(members) {
  // for (const member of members) {
  //   console.log(member);
  // }

  try {
    for (const member of members) {
      console.log(member);
    }
  } catch (error) {
    console.error(err);
    alert(`${err.name}가 발생했습니다.`);
  }
}

const oldTeam = ["넌적혈구", "스기따라", "행섭", "양천", "데셔"];
printMembers(oldTeam);

const Team = { name: "메롱팟" };
printMembers(Team);

const youngTeam = ["찌듕", "힝카인"];
printMembers(youngTeam);

실행 결과, alert 메시지가 등장하면서 확인을 누르면

catch문을 통해 에러가 다뤄졌기 때문에

이후 youngTeam도 정상적으로 출력이 된 것을 확인할 수 있다.

이렇게 trycatch문을 활용하여 

훨씬 안정적인 프로그램을 만들었다.


try...catch문 사용 문제점

try catch문도 결국은 각각의 코드 블록으로 이루어져 있기 때문에

변수를 선언하면 catch문 안에서 사용할 수 없다.

무슨 뜻이 예시를 보자면

// try catch문 활용
try {
  const myName = "SeopE";
} catch (error) {
  console.error(error);
  console.log(myName)
}

 

myName 변수를 try문 안에서 선언한 상태에서

try문도 결국은 중괄호로 감싸진 코드 블록이기 때문에

try문에서 선언한 myName 변수는 catch문 안에서도 사용할 수 없고

또한 try 바깥에서도 사용할 수 없다.

 

그래서 let이나 const 처럼 블록 스코프를 갖는 변수를 활용할 때

각 코드 블록 안에서의 스코프를 잘 생객해야한다.

 

결론은 try catch문은 실행이 가능한 코드 내에서의 에러를 다루며

실행이 가능한 코드에서 발생한 에러를 다루는 과정을

"예외 처리(Exception Handling)" 이라고 부른다.

 


finally문

finally문은 try catch문이 끝난 다음에

최종적으로 실행될 코드를 다룰 때 활용하며 문법은 다음과 같다.

try {
  // 실행할 코드
} catch (err) {
  // 에러가 발생했을 때 실행할 코드
} finally {
  // 항상 실행할 코드
}

try문에서 에러가 발생하지 않는다면 try문의 코드가 모두 실행된 다음에,

try문에서 에러가 발생한다면 catch문의 코드가 모두 실행된 다음

실행할 코드를 finally문에 작성한다.

 

function printMembers(...members) {
  for (const member of members) {
    console.log(member);
  }
}

try {
  printMembers("행섭", "섭이", "쑹빵");
} catch (err) {
  alert("에러가 발생했습니다!");
  console.error(err);
} finally {
  const end = new Date();
  const msg = `코드 실행을 완료한 시각은 ${end.toLocaleString()}입니다.`;
  console.log(msg);
}

즉 finally문은 try문에서 어떤 코드를 실행할 때 에러 여부와 상관 없이 

항상 실행할 코드를 작성하는 문법이다.


finally문 - 에러

finally문에서 에러가 발생한 경우는 위쪽 catch문으로 넘어가진 않고

finally 문에서도 에러 처리가 필요한 경우에는 

다음과 같이 try catch문을 중첩해서 활용한다.

try {
  try {
    // 실행할 코드
  } catch (err) {
    // 에러가 발생했을 때 실행할 코드
  } finally {
    // 항상 실행할 코드
  }
} catch (err) {
  // finally문에서 에러가 발생했을 때 실행할 코드
}

▶ Notion

https://purrfect-gargoyle-935.notion.site/try-catch-157e9530b3e1806284fff42898598c56?pvs=4

 

try…catch | Notion

문제

purrfect-gargoyle-935.notion.site

 

반응형