JS(Section. 11 문제들에 대비하기)

짜스의 하루 ·2024년 4월 25일

에러 핸들링

🐛 에러 핸들링 error handling 의 필요성
--> 에러/에러 error 발생에 대비하지 않으면 프로그램이 종료되고 만다.

  • split() 메서드는 문자열에 대해서만 작동한다. 그러나 3은 숫자이므로 문자열이 아니다.
  • 따라서 split() 메서드를 3에 직접 호출하면 TypeError가 발생한다.
  • 에러가 발생한 이후의 코드는 실행되지 않는 것을 확인할 수 있다.

I. 자바스크립트의 에러 핸들링
1 . try ... catch
예외적인 상황이 예상될 때 코드를 감싸는데 사용된다.
try 블록 안에 예외가 발생할 수 있는 코드를 넣고, 예외가 발생할 경우 catch 블록에서 예외를 처리한다.

try 블록 :

  • 에러 발생 여지가 있는 코드 포함
  • 이곳에서 발생한 에러는 프로그램을 멈추지 않음

catch 블록 :

  • 에러 발생시 실행할 코드 포함
  • 발생한 오류 객체를 인자로 받음

  • 주어진 배열(arr)의 각 요소를 문자열로 변환한 후, getLetterArray 함수를 통해 문자열을 문자 단위로 나누어 출력한다.
  • 여기서는 try...catch 블록을 사용하여 예외 처리를 한다. 만약 예외가 발생하면, 콘솔에 에러 메시지를 출력하고 빈 배열을 반환한다.
  • 123은 숫자이며, 숫자에는 split 메서드가 없다. 따라서 split() 메서드를 123에 직접 호출하면 TypeError가 발생한다.

2 . try ... catch ... finally
finally 블록

  • 오류가 발생 여부와 관계없이 (무조건) 한 번 실행되는 코드 포함
  • 아래와 같은 경우 널리 사용

  • connect() 함수를 호출하여 통신을 연결합니다.
  • try...catch...finally 구문을 사용하여 문자열을 배열로 변환하여 전송하는 과정을 수행한다.
  • try 블록에서는 문자열을 배열로 변환하여 전송하고, 성공 여부를 반환한다.
    ---> 만약 예외가 발생하면 catch 블록에서 해당 예외를 처리하고 false를 반환한다.
  • finally 블록에서는 전송 성공 여부와 관계없이 통신을 해제한다.
  • 배열로 변환 및 전송이 완료된 후, 전송 성공 여부를 반환한다.
  • 또한, forEach 반복문을 사용하여 주어진 배열의 각 요소를 sendStringAsArray 함수에 전달하고, 전송이 성공했는지 여부에 따라 성공 또는 실패 메시지를 출력한다.

II. Error 객체

  • 에러 발생 시 던져지는 throw 객체
  • 에러에 대한 정보를 담고 있음
    💡 에러가 발생하지 않아도, 직접 생성하여 던지기 가능
    👉 MDN 문서 보기

1 . 기본 생성과 사용법

  • new Error()를 사용하여 에러 객체를 생성하고, 생성된 객체를 console.error()를 통해 출력한다.

  • 이렇게 casse 를 입력하여 오류의 원인을 명시할 수도 있다.
    단순히 오류를 출력할 떄에는 뜨지 않지만, error.cause를 통해서 어떤 오류인지 알 수 있다.

  • 에러 자체를 로그 출력하면 나오것 또한 확인할 수 있다.

⭐ 의도적으로 에러 발생시키기

2 . 에러의 여러 종류
⭐ 아래의 에러들은 모두 Error부터 상속받음


1 . 자료형에 맞지 않는 메서드 호출 : (3).split('');는 숫자 3에 split() 메서드를 호출하려고 하기 때문에 TypeError가 발생한다. split()은 문자열에서만 사용할 수 있는 메서드이다.
2 . 선언되지 않은 함수 호출 : hello();는 선언되지 않은 함수인 hello()를 호출하려고 하기 때문에 ReferenceError가 발생한다. 해당 함수가 정의되지 않았기 때문에 호출할 수 없다.
3 . 부적절한 숫자를 인자로 전달: (123.45).toFixed(-1);는 음수를 인자로 전달하여 부적절한 호출을 하고 있다. toFixed() 메서드의 인자는 0 이상의 정수이어야 하지만, 여기서는 음수가 전달되었기 때문에 RangeError가 발생한다.

💡 오류에 종류에 따라 대처하기

💡 직접 오류를 생성하여 던지기
--> 컴퓨터가 인지하지 못하는 에러 수동 발생

  • 매개변수 date가 숫자가 아니면 TypeError를 발생.
  • 매개변수 date가 1부터 12 사이의 숫자가 아니면 RangeError를 발생
  • 유효한 월이 입력되면 해당 월을 당번으로 등록하는 메시지를 출력

3 . 커스텀 에러 만들기
커스텀 에러는 기본적으로 내장된 Error 객체를 확장하여 만든 사용자 지정 에러이다. 이를 통해 에러의 종류를 세분화하거나 추가적인 정보를 제공할 수 있다.

  • 커스텀 에러 클래스인 CustomError를 정의하고, 이를 활용하여 특정 조건에서 예외를 발생시키는 validateNumber 함수를 정의한다.

  • CustomError 클래스는 내장된 Error 객체를 상속하여 만들어졌다. 이 클래스는 생성자를 통해 에러 메시지를 전달받아 속성을 설정하고, 스택 트레이스를 캡처한다.

  • 스택 트레이스는 프로그램이 실행되는 동안 함수 호출의 경로를 기록한 것이다. 예를 들어, 함수 A에서 함수 B를 호출하고, 함수 B에서 함수 C를 호출한 경우, 스택 트레이스는 함수 호출 경로를 A → B → C와 같이 나타낸다.

  • validateNumber 함수는 매개변수로 전달된 값이 숫자가 아닌 경우, CustomError를 발생시킨다. 이 함수는 매개변수로 전달된 값을 검증하여 숫자가 아닌 경우 예외를 발생시키지만, 숫자인 경우는 해당 값을 반환한다.

  • try...catch 블록을 사용하여 validateNumber 함수를 호출하고, 발생한 예외를 처리한다. 만약 숫자가 아닌 값을 전달하면 CustomError가 발생하고, 해당 에러 객체의 이름과 메시지를 출력한다.

III. 에러 버블링 error bubbling
다른 함수를 호출했을 때

  • 에러 발생시 해당 함수에서 잡지 않으면 호출한 곳으로 던져짐
  • 다중 호출시 에러를 핸들링하는 코드가 있는 호출자까지 전달됨

에러 버블링은 자바스크립트에서 예외가 발생한 후 그것이 호출 스택을 따라 상위 호출자에게 전파되는 과정을 말한다. 이 과정은 예외가 발생한 지점에서부터 상위 함수들로 거슬러 올라가면서 예외를 처리할 수 있는 곳을 찾는 것을 의미한다.

  • 호출 스택: 프로그램이 실행되면서 함수가 호출될 때마다 호출 스택에 해당 함수의 정보가 쌓인다. 이 호출 스택을 따라 예외는 전파된다.

  • 상위 호출자로 전파: 예외가 발생하면 해당 지점에서부터 호출 스택을 따라 상위 호출자로 전파된다. 이 과정은 호출 스택의 가장 꼭대기에 있는 함수부터 시작되며, 상위 함수로 계속해서 전파된다.

  • 예외 처리: 예외가 전파되는 동안 상위 호출자 중에서 예외를 처리할 수 있는 곳을 찾는다. 이를 통해 프로그램의 안정성을 유지하고, 예외 상황을 적절하게 처리할 수 있다.

  • Unhandled Exception: 만약 예외가 호출 스택의 가장 꼭대기까지 전파되어도 처리되지 않는다면, 이는 "Unhandled Exception"이 되며, 프로그램이 중단될 수 있다.

  • ⭐ 에러는 가능한 발생 곳 가까이서 처리하는 것이 좋다


엄격모드

엄격 모드 strict mode
: JavaScript 엔진이 코드를 보다 엄격하게 해석하고 실행한다. 이를 통해 코드의 안전성을 높이고 예기치 않은 동작을 방지할 수 있다.
: 'use strict'--> 디렉티브를 코드의 맨 위에 추가함으로써 활성화할 수 있다. 함수 내에서만 엄격 모드를 활성화하려면 함수 내부에 'use strict' 디렉티브를 추가하면 된다.

🪖 엄격 모드의 적용방법과 그 효과들 예시

1 . 선언되지 않은 변수 사용시 오류 발생 + 범위별 적용 방법

x = 2;
console.log(x);

const 나 let으로 선언해주지 않아도 오류가 발생하지 않고 2가 출력된다.

를 출력하게 되면, x가 정의되지 않닸다. 라는 오류 메세지와 함께 오류가 출력되는 것을 확인할 수 있다.

이와 같이 const로 x를 정의해두면, 다시 정확하게 출력할 수 있다는 것을 확인할 수 있다!

  • 'use strict' 는 위와 같이 자바스크립트 문서 최상단에 작성해야 한다 --> 문서 전체에 적용
  • 문서, script 태그별로만 적용 - 여러 .js파일이 페이지에 사용될 시 각각 작성해야 한다!


위 코드를 살펴보면, 'use strict'를 적용하지 않았던, notDec1의 경우, console.log(notDec1)이 출력된 것을 확인할 수 있지만,
'use strict' 가 적용된 stritFunc()의 경우, notDec2를 const , let으로 정의를 하지 않았기 때문에, 오류가 발생하는 것을 볼 수 있다.

2 . 변수, 함수, 인자 등 삭제불가한 것을 삭제시 오류 발생

  • 실제로 delete 연산자로 삭제되지 않지만 오류가 발생하지 않는 이유는 delete 연산자가 변수에 적용되어도 엄격 모드에서는 그것을 무시하기 때문이다. 이는 변수에 대한 delete 연산이 항상 실패하기 때문에, 실제로 삭제되지 않고 그냥 무시되는 행동을 한다. --> 오류가 발생하지 않는다.

  • 엄격 모드에서 delete 연산자로 변수를 삭제하려고 시도하면 오류가 발생한다. --> JavaScript의 엄격 모드에서는 변수 삭제가 허용되지 않는다.

3 . 인자명 중복시 오류 발생

  • ( x+y)의 add 함수를 계획하려다가 오타가 나버렸다. 하지만, 오류가 발생하지 않고, 3+ 3으로 출력되는 것을 볼 수 있다.
  • 'use strict'를 실행해보니, parameter의 이름이 오류가 났다며 오류를 발생해주어 나의 오타 부분을 잡아낼 수 있었다

💡 실무에서의 엄격 모드

  • 클래스나 모듈(등 ES6와 그 이후의 기능들) 사용시 엄격 모드가 기본으로 적용됨
  • 🪄 모든 문제를 방지하는 수단이 되지 않음 기억
  • ⚠️ 기존 코드에 엄격모드 적용시 주의 - 예기치 못한 오류 발생 가능

옵셔널 체이닝

  • 옵셔널 체이닝(optional chaining)은 JavaScript에서 객체의 속성에 안전하게 접근할 수 있도록 도와주는 문법이다.
  • 이 문법은 객체의 속성을 접근할 때 해당 속성이 존재하지 않는 경우에 발생할 수 있는 TypeError를 방지한다.

옵셔널 체이닝?. 연산자를 사용하여 구현된다. 이 연산자는 체인 중간에 속성이나 메서드가 존재하지 않는 경우에도 프로그램이 중단되지 않고 그저 undefined를 반환한다. 따라서 코드의 실행을 중단시키지 않고 안전하게 속성에 접근할 수 있다.

예를 들어서 살펴보자

const rand = () => Math.random() < 0.75;

const notSure = () => rand() ? {
  prop1: rand() ? {
    prop2: rand() ? {
      prop3: rand() ? '성공!' : undefined
    } : undefined
  } : undefined
} : undefined;
  • rand() 함수는 75%의 확률로 true를 반환하고, 나머지 25%의 확률로 false를 반환한다. 이 함수를 통해 무작위로 true 또는 false 값을 생성한다.
  • notSure 함수는 위에서 정의한 rand 함수를 이용하여 무작위로 객체를 생성한다. 이 객체는 다음과 같은 구조를 가진다:
    • prop1: 객체 또는 undefined를 가질 수 있다. rand() 함수의 반환 값에 따라 존재할 수도, 존재하지 않을 수도 있다.
    • prop2: 객체 또는 undefined를 가질 수 있다. prop1이 존재하는 경우에만 존재할 수 있으며, 무작위로 결정된다.
    • prop3: 문자열 '성공!' 또는 undefined를 가질 수 있다. prop2가 존재하는 경우에만 존재할 수 있으며, 무작위로 결정된다.

JSON.stringify(notSure())를 호출하면 notSure() 함수가 반환하는 값을 JSON 문자열로 변환하여 출력한다. 이를 통해 notSure() 함수가 반환하는 값을 확인할 수 있다.

하지만 notSure() 함수는 무작위로 객체를 생성하기 때문에 호출할 때마다 결과가 달라질 수 있다. 따라서 호출할 때마다 다른 결과를 얻는다.


result.prop1.prop2.prop3에 접근하려 하지만, 이 속성이 존재하지 않을 수도 있으므로 접근 시도가 실패할 수 있다. --> 이 경우 에러가 발생한다.

방법1.

방법2.

방법3.

3가지 방법을 모두 살펴보았을 때, 세가지 모두 가독성이 떨어지거나 반복적인 부분이 많이 보인다.

?. - 옵셔널 체이닝 optional chaining 연산자

  • 호출 대상이 undefined나 null이어도 오류를 발생시키지 않음 - 대신 undefined 반환
  • 있을지 없을지 모르는 것으로부터 값을 읽거나 실행할 때 사용

  • Optional Chaining은 속성이나 메서드 호출을 안전하게 수행하고, 중간에 null 또는 undefined가 발생할 경우 에러를 방지
  • undef ?.x : undef 변수가 undefined이므로 undef.x를 참조할 때 에러가 발생하지 않고 undefined를 반환한다.
  • undef ?.['x'] : 위와 동일하게 undef['x']를 참조하므로 undefined를 반환한다.
  • undef ?.[1] : undef가 undefined이므로 undef[1]을 참조할 때 에러가 발생하지 않고 undefined를 반환한다.
  • {}.func?.(): 빈 객체 {}에는 func라는 메서드가 없으므로 undefined를 반환한다. 이후 ?.()를 통해 에러가 발생하지 않고 그냥 undefined가 반환된다.


result?.prop1?.prop2?.prop3은 아래와 같이 해석된다:

  • result 객체의 prop1 속성에 접근한다.
  • prop1 속성이 존재하면, prop1 객체의 prop2 속성에 접근한다.
  • prop2 속성이 존재하면, prop2 객체의 prop3 속성에 접근한다.
  • 만약 prop1, prop2, prop3 중 하나라도 존재하지 않으면, 에러가 발생하지 않고 그냥 undefined를 반환한다.
  • 이렇게 옵셔널 체이닝을 사용하면 속성이나 메서드가 없는 경우에도 코드가 안전하게 실행된다.
  • 만약 result, prop1, prop2 중 하나라도 undefined이거나 null이면, 그 이후의 속성에 접근하지 않고 그냥 undefined를 반환한다.

예시1

1 . user.address.street에 접근하려 할 때:
console.log(user.address.street) 로 접근하게 되면, 오류가 발생하게 된다.

업로드중..

  • 여기서 user가 존재하고 address가 존재하면 street에 접근하여 값을 가져오고, 그렇지 않으면 그냥 undefined를 반환하게 된다.

업로드중..
이 경우에는 옵셔널 체이닝을 사용하여 street에 안전하게 접근할 수 있다.
따라서 옵셔널 체이닝을 사용하면 객체의 중첩된 속성에 안전하게 접근할 수 있으며, 속성이 존재하지 않을 때 발생할 수 있는 에러를 방지할 수 있다.


퀴즈

1 .NetworkError 란 이름의 사용자 정의 Error 클래스를 만들어보자
기존의 Error 를 확장하여, statusCode 란 필드를 추가로 갖는 클래스이다.

class NetWorkError extends Error {
    constructor(message, statusCode){
        super(message);
        this.name = 'NetWorkError';
        this.statusCode = statusCode;
    }
}

NetWorkError 클래스는 Error 클래스를 확장하고 있으며, 사용자 정의 에러 객체를 만들어 네트워크 관련 에러를 처리하기 위한 것으로 보인다.

  • message : 에러 메시지를 저장하는 속성이다. 이는 부모 클래스인 Error 클래스에서 상속된다.
  • statusCode: 네트워크 에러에 해당하는 HTTP 상태 코드를 저장하는 속성이다.
  • constructor 메서드는 이 클래스의 생성자이다. 이 생성자는 두 개의 매개변수 message와 statusCode를 받아와서 부모 클래스인 Error의 생성자를 호출하여 에러 메시지를 설정 한다.
  • 그 후 this.name 속성을 'NetWorkError'로 설정하여 이 에러가 NetWorkError 클래스의 인스턴스임을 나타낸다. 마지막으로 statusCode 속성을 설정하여 에러 객체에 HTTP 상태 코드를 추가한다.

JavaScript의 내장 클래스인 Error 클래스는 에러 객체를 생성할 때 에러 메시지를 설정하기 위해 message 매개변수를 받는 생성자를 갖고 있다.

따라서 super(message) 를 호출함으로써 NetWorkError 클래스의 생성자에서는 Error 클래스의 생성자를 호출하여 에러 메시지를 설정할 수 있다.
이렇게 함으로써 NetWorkError 클래스의 인스턴스를 생성할 때 사용자가 제공한 메시지를 해당 에러 객체에 설정할 수 있다.

2 . 배열은 빈 배열 일 수도 있고, 다른 내용의 값들이 들어 있을 수도 있다.
배열의 내용을 모르는 상태에서, 배열의 첫번째 객체가 name 프로퍼티를 갖고 있을 시 그 값을 모두 대문자로 출력하고, 배열이 비었거나 첫 값의 형태가 다르다면 오류 없이 undefined 를 출력하는 코드를 작성해보자.

const products = [
  { name: 'Phone', price: 700 },
  { name: 'Tablet', price: 900 }
];

console.log(
    products[0]?.name.toUpperCase()
);
  • products 배열에서 첫 번째 요소인 products[0]에 접근한다.
  • 해당 요소가 존재하면(products[0]이 undefined나 null이 아닌 경우), name 속성에 접근한다.
  • name 속성이 존재하는 경우, 문자열을 대문자로 변환한 후 출력한다. 만약 name 속성이 존재하지 않거나 products[0]이 존재하지 않는다면 undefined가 반환된다.
profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글