JavaScript - 오류 확장

안녕하세요, 미래의 JavaScript 마법사 여러분! 오늘 우리는 JavaScript에서 오류를 확장하는 흥미로운 세상으로 뛰어들어 보겠습니다. 프로그래밍에 새로운 사람이라면 걱정하지 마세요 - 이 모험을 안내해 드릴 친절한 안내자가 여러분입니다. 이 수업이 끝나면, 프로처럼 자신만의 커스텀 오류를 만드는 법을 배울 것입니다!

JavaScript - Extending Errors

오류 클래스 확장: 커스텀 오류 생성

기본적인 내용부터 시작해 보겠습니다. JavaScript에서 우리는 오류 객체를 만들기 위해 내장된 Error 클래스를 사용할 수 있습니다. 하지만 때로는 우리의 애플리케이션을 위해 더 구체적인 오류가 필요할 수 있습니다. 여기서 Error 클래스를 확장하는 것이 유용해집니다!

왜 오류를 확장하죠?

culinary app을 개발 중이라고 가정해 봅시다. 부엌에서 벌어지는 특정 사고에 대해 특정 오류를 만들고 싶다면 어떨까요? 일반적인 Error를 사용할 수도 있지만, BurnedFoodErrorOverseasonedError가 있으면 좋지 않을까요? 우리가 이제 배우게 될 것입니다!

오류 확장의 기본 문법

간단한 예제로 시작해 보겠습니다:

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

이를 해부해 보겠습니다:

  1. class 키워드를 사용하여 새로운 오류 클래스를 정의합니다.
  2. extends Error는 우리의 새로운 클래스가 내장된 Error 클래스를 상속해야 한다는 것을 JavaScript에 알립니다.
  3. constructor에서 super(message)를 호출하여 부모 Error 클래스가 올바르게 초기화되도록 합니다.
  4. this.name을 설정하여 우리의 오류에 특정 이름을 부여합니다.

이제 이를 어떻게 사용할 수 있는지 보겠습니다:

try {
throw new KitchenError("The spaghetti is stuck to the ceiling!");
} catch (error) {
console.log(error.name); // 출력: KitchenError
console.log(error.message); // 출력: The spaghetti is stuck to the ceiling!
}

커스텀 속성 추가

오류를 확장하는 것의 가장 멋진 점 중 하나는 우리가 자신만의 커스텀 속성을 추가할 수 있다는 것입니다. 우리의 KitchenError를 보강해 보겠습니다:

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

try {
throw new KitchenError("It's burning!", "lasagna");
} catch (error) {
console.log(`Oh no! The ${error.dish} is in trouble: ${error.message}`);
// 출력: Oh no! The lasagna is in trouble: It's burning!
}

이 예제에서 우리는 dish 속성을 추가하여 부엌 사고에 대해 더 많은 맥락을 제공할 수 있습니다!

특정 오류 유형 생성

이제 Error 클래스를 확장하는 법을 알고 있으므로, 부엌 앱을 위한 몇 가지 특정 오류 유형을 만들어 보겠습니다:

class BurnedFoodError extends KitchenError {
constructor(dish) {
super(`The ${dish} is burned to a crisp!`, dish);
this.name = 'BurnedFoodError';
}
}

class OverseasonedError extends KitchenError {
constructor(dish, seasoning) {
super(`The ${dish} is over-seasoned with ${seasoning}!`, dish);
this.name = 'OverseasonedError';
this.seasoning = seasoning;
}
}

이제 이 특정 오류 유형을 코드에서 사용할 수 있습니다:

function cookDinner(dish, seasoning) {
if (Math.random() < 0.5) {
throw new BurnedFoodError(dish);
} else if (Math.random() < 0.5) {
throw new OverseasonedError(dish, seasoning);
}
console.log(`Your ${dish} is perfectly cooked!`);
}

try {
cookDinner("steak", "salt");
} catch (error) {
if (error instanceof BurnedFoodError) {
console.log(`Oops! ${error.message} Time to order takeout.`);
} else if (error instanceof OverseasonedError) {
console.log(`Yikes! ${error.message} Maybe use less ${error.seasoning} next time.`);
} else {
console.log("Something went wrong in the kitchen!");
}
}

이 코드는 요리의 불확실성을 시뮬레이션하고(어떤 사람들에게는!), 다른 유형의 오류를 다른 방법으로 처리할 수 있음을 보여줍니다.

다단계 상속

이제 우리의 오류 계층 구조를 다음 단계로 업그레이드해 보겠습니다 - 문자 그대로 말이죠! 우리는 오류 유형의 체인을 만들 수 있으며, 이를 다단계 상속이라고 합니다.

부엌 오류 시스템을 확장해 보겠습니다:

class KitchenApplianceError extends KitchenError {
constructor(message, appliance) {
super(message);
this.name = 'KitchenApplianceError';
this.appliance = appliance;
}
}

class OvenError extends KitchenApplianceError {
constructor(message) {
super(message, 'oven');
this.name = 'OvenError';
}
}

class MicrowaveError extends KitchenApplianceError {
constructor(message) {
super(message, 'microwave');
this.name = 'MicrowaveError';
}
}

이 예제에서:

  • KitchenApplianceErrorKitchenError를 상속합니다.
  • OvenErrorMicrowaveError는 모두 KitchenApplianceError를 상속합니다.

이 계층 구조를 어떻게 사용할 수 있는지 보겠습니다:

function useAppliance(appliance) {
if (appliance === 'oven') {
throw new OvenError("The oven won't heat up!");
} else if (appliance === 'microwave') {
throw new MicrowaveError("The microwave is making strange noises!");
}
}

try {
useAppliance('oven');
} catch (error) {
if (error instanceof OvenError) {
console.log(`Oven problem: ${error.message}`);
} else if (error instanceof MicrowaveError) {
console.log(`Microwave issue: ${error.message}`);
} else if (error instanceof KitchenApplianceError) {
console.log(`General appliance error with the ${error.appliance}: ${error.message}`);
} else if (error instanceof KitchenError) {
console.log(`Kitchen error: ${error.message}`);
} else {
console.log(`Unexpected error: ${error.message}`);
}
}

이 다단계 상속을 통해 우리는 매우 구체적인 오류 유형을 만들 수 있으면서도, 논리적인 계층 구조를 유지할 수 있습니다. 우리는 가장 구체적인(OvenError)에서 가장 일반적인(Error)까지 다양한 수준에서 오류를 잡을 수 있습니다.

메서드 표

우리가 커스텀 오류에서 사용한 주요 메서드와 속성을 요약한 표입니다:

메서드/속성 설명 예제
constructor() 오류 객체 초기화 constructor(message, dish)
super() 부모 클래스 생성자 호출 super(message)
this.name 오류 이름 설정 this.name = 'KitchenError'
this.[custom] 커스텀 속성 추가 this.dish = dish
instanceof 객체가 클래스의 인스턴스인지 확인 if (error instanceof OvenError)

오류를 확장하는 것은 단순히 오류의 예쁜 이름을 만드는 것에 관한 것이 아니라, 코드에서 다양한 오류 유형을 구조화된 방식으로 처리하는 것입니다. 이를 통해 디버깅을 더 쉽게 하고, 오류 메시지를 더 구체적이고 유용하게 만들 수 있습니다.

따라서 다음 번에 코드를 작성할 때 오류가 발생하면, 일반적인 오류를 던지지 말고 커스텀 오류를 만들어 보세요! 누구나 당신의 CodeSpaghettiError를 개발 팀에서 이야기할 만한 주제로 만들 수 있습니다. 행복하게 코딩하시고, 모든 오류가 완벽하게 확장되길 바랍니다!

Credits: Image by storyset