Интерпретатор JavaScript генерирует ошибки для ряда ситуаций, например, при вызове несуществующей функции, при повторном присвоении константе значения и т.д. Но при необходимости мы сами можем генерировать ошибки и определить условия, когда будет генерироваться ошибка.
Например, рассмотрим следующую ситуацию:
class Person{ constructor(name, age){ this.name = name; this.age = age; } print(){ console.log(`Name: ${this.name} Age: ${this.age}`);} } const tom = new Person("Tom", -123); tom.print(); // Name: Tom Age: -123
Класс Person описывает человека. В конструкторе класс получает значения для свойств name (имя) и age (возраст). Исходя из здравого смысла мы понимаем, что возраст не может быть отрицательным. Тем не менее пока, исходя из логики класса, ничего не мешает при создании объекта Person передать ему для возраста отрицательное значение. С точки зрения интерпретатора JavaScript ошибки нет, однако с точки логики и здравого смысла - это ошибка. Как исправить эту ситуацию? Есть различные способы, и один из них заключается в генерации исключения.
Для генерации исключения применяется оператор throw, после которого указывается информация об ошибке:
throw информация_об_ошибке;
Информация об ошибке может представлять любой объект.
Так, сгенерируем исключение при передаче в конструктор Person отрицательного значения для свойства age:
class Person{ constructor(name, age){ if(age < 0) throw "Возраст должен быть положительным"; this.name = name; this.age = age; } print(){ console.log(`Name: ${this.name} Age: ${this.age}`);} } const tom = new Person("Tom", -123); // Uncaught Возраст должен быть положительным tom.print();
В итоге при вызове конструктора Person будет сгенерировано исключение и программа завершится ошибкой. А на консоли браузера мы увидим информацию
об ошибке, которая указана после оператора throw
:
Uncaught Возраст должен быть положительным
Как и в общем случае мы можем обработать эту ошибку с помощью блока try...catch:
class Person{ constructor(name, age){ if(age < 0) throw "Возраст должен быть положительным"; this.name = name; this.age = age; } print(){ console.log(`Name: ${this.name} Age: ${this.age}`);} } try{ const tom = new Person("Tom", -123); // Uncaught Возраст должен быть положительным tom.print(); } catch(error){ console.log("Произошла ошибка"); console.log(error); // Возраст должен быть положительным }
Оператор throw может вызываться в различных контекстах, например, в том же блоке try:
try{ throw "Непредвиденная ошибка!"; } catch(error){ console.log(error); // Непредвиденная ошибка! }
Это может быть полезно по ряду причин. Во-первых, мы можем тут же обработать ошибку. Во-вторых, мы можем определить с помощью блока finally некоторые завершающие действия, которые будут выполняться, даже если сгенерирована ошибка. Например:
// класс условной базы данных class Database{ constructor(){ this.data = ["Tom", "Sam", "Bob"]; } // получение данных getItem(index){ this.open(); if(index > 0 && index < this.data.length) return this.data[index]; else throw "Некорректный индекс"; this.close(); // при генерации исключения эта строка не будет выполняться } // открытие бд open(){ console.log("Подключение к базе данных установлено"); } // закрытие бд close(){ console.log("Подключение к базе данных закрыто"); } } const db = new Database(); try { db.getItem(5); // возвращаем полученный элемент } catch(err) { console.error(err); // если произошла ошибка обрабатываем ее }
Здесь определен класс Database - класс условной базы данных. Все данные хранятся в массиве data. Для взаимодействия с базой данных определены три метода. Методы open и close условно открывают и закрывают подключение к базе данных. Метод getItem получает по индексу элемент из массива data. Если же индекс некорректный, то генерируется ошибка. При этом до получения элемента по индексу метод getItem должен открыть подключение методом open, а после получения - закрыть методом close. Однако в примере выше при генерации ошибки закрытия подключения не произойдет:
else throw "Некорректный индекс"; this.close(); // при генерации исключения эта строка не будет выполняться
В итоге при передаче в метод getItem некорректного индекса консольный вывод программы будет следующим:
Подключение к базе данных установлено
Некорректный индекс
Однако что делать, если нам все таки надо вызвать метод close? Мы можем поместить его вызов в блок finally:
class Database{ constructor(){ this.data = ["Tom", "Sam", "Bob"]; } // получение данных getItem(index){ this.open(); try{ if(index > 0 && index < this.data.length) return this.data[index]; else throw "Некорректный индекс"; } finally{ // даже если сгенерирована ошибка, то этот блок выполняется this.close(); // при генерации исключения эта строка также будет выполняться } } // открытие бд open(){ console.log("Подключение к базе данных установлено"); } // закрытие бд close(){ console.log("Подключение к базе данных закрыто"); } } const db = new Database(); try { db.getItem(5); // возвращаем полученный элемент } catch(err) { console.error(err); // если произошла ошибка обрабатываем ее }
И теперь консольный вызов будет иным:
Подключение к базе данных установлено
Подключение к базе данных закрыто
Некорректный индекс