[JS] 14 - 예외처리

Jang·2022년 9월 5일
0

학원

목록 보기
7/26
  • 예외처리를 하는 이유
    • 예외처리를 하지 않으면 에러가 나는 순간 프로그램 실행이 중단이 되지만,
      예외처리를 만들어주면 중간에 어느 구간에서 어떤 에러가 발생했는지 표시가 가능하고 나머지 코드를 실행시킬 수 있기 때문.

  • 고전적 예외처리

    • 개발자가 원하지 않는 상황을 예외시키기 위해 if문으로 대체 -> 예외처리

      /** 조건문을 사용한 고전적 예외처리 */
      // 프로그램이 실행되기에 적합하지 않은 파라미터가 전달된 경우 미리 약속된 값을 리턴
      // -> 프로그램의 성공 실패 여부를 리터값으로 판단하는 경우
      function foo(x, y) {
        if (x < 0 && y < 0) {
          return 0;
        }
        return x + y;
      }
      
      // 정상호출 상황
      console.log(foo(10, 20));
      // 비정상 호출 상황
      console.log(foo(-1, -2));
      
      // 비정상 상황에 대한 고전적 처리 방법
      const k = foo(-1, -2);
      
      // 에러 상황에 대한 대응(메시지 처리)을 함수를 호출하는 곳에서 해야 한다.
      if (k == 0) {
        console.log("x와 y가 0보다 작습니다.");
      } else {
        console.log(k);
      }
    • 모듈을 이용했을때 추가적으로 에러 대응을 입력해줘야 하는 단점이 생김.


  • try,catch

    • [에러의 종류]

      1. Syntax Error : 문법에러. 코딩상의 실수이므로 수정하지 않으면 프로그램이 동작하지 않음.
      2. Runtime Error : 프로그램 작성 과정에서 논리상의 오류로 미처 대응하지 못한 상황이 발생하는 경우. -> 처리하지 않을 경우 프로그램이 중단된다.
      const data = [1, 2, 3];
      console.log("배열 탐색 시작");
      
      // 먼저, try {...} 안의 코드가 실행된다.
      // 에러가 없다면, try 안의 마지막 줄까지 실행되고, catch 블록은 건너뛴다.
      // 에러가 있다면, try 안 코드의 실행이 중단되고, catch(err) 블록으로 제어 흐름이 넘어간다.
      // 변수 err(아무 이름이나 사용 가능)는 무슨 일이 일어났는지에 대한 설명이 담긴 에러 객체를 포함한다.
      try {
        for (let i = 0; i < 10; i++) {
          console.log(data[i].toFixed(2));
        }
      
        console.log("try 블록 실행 완료~!!!");
      } catch (err) {
        console.group("%s 에러발생", err.name);
        console.error(err.message);
        console.groupEnd();
        // 에러정보 전체
        // console.error(err);
      } finally {
        // 에러의 발생 여부에 상관 없이 무조건 맨 마지막에 실행되는 블록.
        // 필요하지 않은 경우 생략할 수 있다.
        console.log("배열 탐색이 종료되었습니다.");
      }
      
      console.log("프로그램 종료");

  • 에러객체

    • 개발자가 직접 정의하는 에러

      // 에러 객체를 생성
      // 생성자 파라미터로 에러의 내용 전달
      let err = new Error("이상한 일이 벌어졌습니다.");
      console.log("에러이름: %s", err.name);
      console.log("에러이름: %s", err.message);
      
      // 개발자가 직접 에러를 발생시킬 수 있다.
      // --> 이 구문을 실제 에러로 인식하기 때문에 프로그램이 이 위치에서 중단된다.
      throw err;
      
      console.log("프로그램 종료");
    • 개발자가 발생시키는 에러에 대한 예외처리

       let err = new Error("이상한 일이 벌어졌습니다.");
      
       try {
         // throw구문은 그 자체를 에러로 인식하기 때문에 try-catch 처리가 가능하다.
         throw err;
       } catch (err) {
         console.log("에러이름: %s", err.name);
         console.log("에러이름: %s", err.message);
       }
      
       // 에러 상황을 try-catch로 처리했으므로 프로그램이 중단되지 않고 무사히 종료할 수 있다.
       console.log("프로그램 종료");

  • 예외 객체를 통한 예외처리

    • try블록 안의 코드는 최소화 하는 것이 프로그램 효율에 좋다.

    • 그래서 k값을 정상적으로 리턴 받았다면 그 결과값을 활용하는 처리는 try블록 밖에서 하는것이 좋다.

    • 에러 점검이 끝난 후 try-catch 블록 밖에서 k값을 활용하려면

    • 변수의 선언 위치가 try블록보다 상위에 위치해야 한다. --> 변수의 스코프 규칙

       function foo(x, y) {
         if (x < 0) {
           // 함수 안에서 에러를 강제로 발생시킬 경우, 이 함수를 호출하는 위치를 에러로 인식한다.
           throw new Error("x가 0보다 작습니다.");
         }
      
         if (y < 0) {
           // 함수 안에서 에러를 강제로 발생시킬 경우, 이 함수를 호출하는 위치를 에러로 인식한다.
           throw new Error("y가 0보다 작습니다.");
         }
      
         return x + y;
       }
      
       // try블록 안의 코드는 최소화 하는 것이 프로그램 효율에 좋다.
       // 그래서 k값을 정상적으로 리턴 받았다면 그 결과값을 활용하는 처리는 try블록 밖에서 하는것이 좋다.
       // 에러 점검이 끝난 후 try-catch 블록 밖에서 k값을 활용하려면
       // 변수의 선언 위치가 try블록보다 상위에 위치해야 한다. --> 변수의 스코프 규칙
       const a = null;
       const b = null;
      
       try {
         a = foo(-1, 10);
       } catch (err) {
         // 이 블록으로 전달되는 err객체는 5라인에서 생성한 Error 클래스의 객체이다.
         console.log("에러이름: %s", err.name);
         console.log("에러이름: %s", err.message);
       }
      
       try {
         b = foo(10, -1);
       } catch (err) {
         // 이 블록으로 전달되는 err객체는 10라인에서 생성한 Error 클래스의 객체이다.
         console.log("에러이름: %s", err.name);
         console.log("에러이름: %s", err.message);
       }
      
       // 코드는 좌우중에서 우변을 먼저 실행하는데 우변에서 에러가 났으므로 변수에 값이 할당되지 않음.
       console.log(a); // null
       console.log(b); // null
      • 코드는 좌우중에서 우변을 먼저 실행하는데 우변에서 에러가 나게 되면 변수에 값이 할당되지 않음.
  • 사용자 정의 에러

    • 에러의 종류를 세분화 하기 위해 기본 Error 클래스의 기능을 확장하여 개발자가 직접 에러에 대한 경우의 수를 정의할 수 있다.

      class XlessError extends Error {
        // 자식 클래스가 생성자를 갖을 경우 부모의 생성자를 반드시 강제호출해야 한다. --> super(...)
        constructor(msg) {
          super(msg);
          super.name = "XlessError";
        }
      }
      
      class YlessError extends Error {
        // 자식 클래스가 생성자를 갖을 경우 부모의 생성자를 반드시 강제호출해야 한다. --> super(...)
        constructor(msg) {
          super(msg);
          super.name = "YlessError";
        }
      }
      
      function foo(x, y) {
        if (x < 0) {
          // 함수 안에서 에러를 강제로 발생시킬 경우, 이 함수를 호출하는 위치를 에러로 인식한다.
          throw new XlessError("x가 0보다 작습니다.");
        }
      
        if (y < 0) {
          // 함수 안에서 에러를 강제로 발생시킬 경우, 이 함수를 호출하는 위치를 에러로 인식한다.
          throw new YlessError("y가 0보다 작습니다.");
        }
      
        return x + y;
      }
      
      const a = null;
      const b = null;
      
      try {
        a = foo(-1, 10);
      } catch (err) {
        console.log("에러이름: %s", err.name);
        console.log("에러내용: %s", err.message);
        console.log(err);
      }
      
      try {
        b = foo(10, -1);
      } catch (err) {
        console.log("에러이름: %s", err.name);
        console.log("에러내용: %s", err.message);
        console.log(err);
      }
      
      console.log(a);
      console.log(b);

  • helper

    • 지금 실력으로 helper 작성은 어렵지만 적어도 내용은 이해하고 설명은 할 수 있을 정도를 목표해야 한다.

0개의 댓글