Генерация ошибок и оператор throw

Последнее обновление: 01.09.2023

Интерпретатор 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..catch..finally

Оператор 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); // если произошла ошибка обрабатываем ее 
}

И теперь консольный вызов будет иным:

Подключение к базе данных установлено
Подключение к базе данных закрыто
Некорректный индекс
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850