JavaScript - Расширение ошибок

Здравствуйте, будущие маги JavaScript! Сегодня мы окунемся в захватывающий мир расширения ошибок в JavaScript. Не волнуйтесь, если вы новички в программировании - я буду вашим дружественным проводником в этом приключении. К концу урока вы сможете создавать свои собственные пользовательские ошибки, как профи!

JavaScript - Extending Errors

Расширение класса Error: Создание пользовательских ошибок

Давайте начнем с азов. В JavaScript у нас есть встроенный класс Error, который мы можем использовать для создания объектов ошибок. Но иногда нам нужны более конкретные ошибки для наших приложений. Вот где расширение класса Error becomes полезным!

Why Extend Errors?

Представьте, что вы создаете кулинарное приложение, и вам нужно создать конкретные ошибки для кулинарных казусов. Вы можете использовать общий Error, но разве не было бы лучше иметь BurnedFoodError или OverseasonedError? Именно это мы и научимся делать!

Основной синтаксис для расширения ошибок

Давайте начнем с простого примера:

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

Разберем это:

  1. Мы используем ключевое слово class для определения нового класса ошибок.
  2. extends Error говорит JavaScript, что наш новый класс должен наследоваться от встроенного класса Error.
  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!
}

Добавление пользовательских свойств

Одна из coolest вещей в расширении ошибок - это возможность добавлять свои собственные пользовательские свойства. Давайте усовершенствуем наш 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 к нашей ошибке. Это позволяет нам предоставить больше контекста о том, что exactly пошло не так в нашей кулинарной катастрофе!

Создание конкретных типов ошибок

Теперь, когда мы знаем, как расширять класс 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';
}
}

В этом примере:

  • KitchenApplianceError наследуется от KitchenError
  • OvenError и MicrowaveError наследуются от 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 станетtemой для обсуждения в вашей команде разработчиков. Удачи в программировании, и пусть все ваши ошибки будут идеально расширены!

Credits: Image by storyset