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

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

try 블록 :
catch 블록 :

try...catch 블록을 사용하여 예외 처리를 한다. 만약 예외가 발생하면, 콘솔에 에러 메시지를 출력하고 빈 배열을 반환한다.2 . try ... catch ... finally 문
finally 블록


II. Error 객체
1 . 기본 생성과 사용법



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

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


1 . 자료형에 맞지 않는 메서드 호출 : (3).split('');는 숫자 3에 split() 메서드를 호출하려고 하기 때문에 TypeError가 발생한다. split()은 문자열에서만 사용할 수 있는 메서드이다.
2 . 선언되지 않은 함수 호출 : hello();는 선언되지 않은 함수인 hello()를 호출하려고 하기 때문에 ReferenceError가 발생한다. 해당 함수가 정의되지 않았기 때문에 호출할 수 없다.
3 . 부적절한 숫자를 인자로 전달: (123.45).toFixed(-1);는 음수를 인자로 전달하여 부적절한 호출을 하고 있다. toFixed() 메서드의 인자는 0 이상의 정수이어야 하지만, 여기서는 음수가 전달되었기 때문에 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'를 적용하지 않았던, notDec1의 경우, console.log(notDec1)이 출력된 것을 확인할 수 있지만,
'use strict' 가 적용된 stritFunc()의 경우, notDec2를 const , let으로 정의를 하지 않았기 때문에, 오류가 발생하는 것을 볼 수 있다.
2 . 변수, 함수, 인자 등 삭제불가한 것을 삭제시 오류 발생


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


💡 실무에서의 엄격 모드
옵셔널 체이닝은 ?. 연산자를 사용하여 구현된다. 이 연산자는 체인 중간에 속성이나 메서드가 존재하지 않는 경우에도 프로그램이 중단되지 않고 그저 undefined를 반환한다. 따라서 코드의 실행을 중단시키지 않고 안전하게 속성에 접근할 수 있다.
예를 들어서 살펴보자
const rand = () => Math.random() < 0.75;
const notSure = () => rand() ? {
prop1: rand() ? {
prop2: rand() ? {
prop3: rand() ? '성공!' : undefined
} : undefined
} : undefined
} : undefined;

JSON.stringify(notSure())를 호출하면 notSure() 함수가 반환하는 값을 JSON 문자열로 변환하여 출력한다. 이를 통해 notSure() 함수가 반환하는 값을 확인할 수 있다.
하지만 notSure() 함수는 무작위로 객체를 생성하기 때문에 호출할 때마다 결과가 달라질 수 있다. 따라서 호출할 때마다 다른 결과를 얻는다.

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

방법2.

방법3.

3가지 방법을 모두 살펴보았을 때, 세가지 모두 가독성이 떨어지거나 반복적인 부분이 많이 보인다.
?. - 옵셔널 체이닝 optional chaining 연산자

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은 아래와 같이 해석된다:
예시1

1 . user.address.street에 접근하려 할 때:
console.log(user.address.street) 로 접근하게 되면, 오류가 발생하게 된다.
이 경우에는 옵셔널 체이닝을 사용하여 street에 안전하게 접근할 수 있다.
따라서 옵셔널 체이닝을 사용하면 객체의 중첩된 속성에 안전하게 접근할 수 있으며, 속성이 존재하지 않을 때 발생할 수 있는 에러를 방지할 수 있다.
1 .NetworkError 란 이름의 사용자 정의 Error 클래스를 만들어보자
기존의 Error 를 확장하여, statusCode 란 필드를 추가로 갖는 클래스이다.
class NetWorkError extends Error {
constructor(message, statusCode){
super(message);
this.name = 'NetWorkError';
this.statusCode = statusCode;
}
}
NetWorkError 클래스는 Error 클래스를 확장하고 있으며, 사용자 정의 에러 객체를 만들어 네트워크 관련 에러를 처리하기 위한 것으로 보인다.
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[0]에 접근한다.