Типы ошибок
В блоке catch мы можем получить информацию об ошибке, которая представляет объект. Все ошибки, которые генерируются интерретатором JavaScript, предоставляют объект типа Error который имеет ряд свойств:
messageсообщение об ошибкеnameтип ошибки
Стоит отметить, что отдельные браузеры поддерживают еще ряд свойств, но их поведение в зависимости от браузера может отличаться:
fileNameназвание файла с кодом JavaScript, где произошла ошибкаlineNumberстрока в файле, где произошла ошибкаcolumnNumberстолбец в строке, где произошла ошибкаstackстек ошибки
Получим данные ошибки, например, при вызове несуществующей функции:
try{
callSomeFunc();
}
catch(error){
console.log("Тип ошибки:", error.name);
console.log("Ошибка:", error.message);
}
Консольный вывод:
Тип ошибки: ReferenceError
Ошибка: callSomeFunc is not defined
Типы ошибок
Выше мы рассмотрели, что генерируемая интерпретатором ошибка представляет тип Error, однако при вызове несуществующей функции генерируется ошибка типа ReferenceError. Дело в том, что тип Error представляет общий тип ошибок. В то же время есть конкретные типы ошибок для определенных ситуаций:
EvalErrorпредставляет ошибку, которая генерируется при выполнении глобальной функцииeval()RangeErrorошибка генерируется, если параметр или переменная, представляют число, которое находится вне некотоого допустимого диапазонаReferenceErrorошибка генерируется при обращении к несуществующей ссылкеSyntaxErrorпредставляет ошибку синтаксисаTypeErrorошибка генерируется, если значение переменной или параметра представляют некорректный тип или пр попытке изменить значение, которое нельзя изменятьURIErrorошибка генерируется при передаче функциямencodeURI()иdecodeURI()некорректных значенийAggregateErrorпредоставляет ошибку, которая объединяет несколько возникших ошибок
Например, при попытке присвоить константе второй раз значение, генерируется ошибка TypeError:
try{
const num = 9;
num = 7;
}
catch(error){
// TypeError
console.log(error.name);
// Assignment to constant variable.
console.log(error.message);
}
Применение типов ошибок
При генерации ошибок мы можем использовать встроенные типы ошибок:
class Person{
constructor(name, age){
if(age < 0) throw new Error("Возраст должен быть положительным");
this.name = name;
this.age = age;
}
print(){ console.log(`Name: ${this.name} Age: ${this.age}`);}
}
try{
const tom = new Person("Tom", -45);
tom.print();
}
catch(error){
// Возраст должен быть положительным
console.log(error.message);
}
Здесь конструктор класса Person принимает значения для имени и возаста человека. Если передан отрицательный возраст, то генерируем ошибку в виде объекта Error. В качестве параметра в конструктор Error передается сообщение об ошибке:
if(age < 0) throw new Error("Возраст должен быть положительным");
В итоге при обработке исключения в блоке catch мы сможем получить переданное сообщение об ошибке. Все остальные типы ошибок в качестве первого параметра в конструкторе также принимают сообщение об ошибке. Сгенерируем несколько типов ошибок:
class Person{
constructor(pName, pAge){
const age = parseInt(pAge);
if(isNaN(age)) throw new TypeError("Возраст должен представлять число");
if(age < 0 || age > 120) throw new RangeError("Возраст должен быть больше 0 и меньше 120");
this.name = pName;
this.age = age;
}
print(){ console.log(`Name: ${this.name} Age: ${this.age}`);}
}
Поскольку для возраста можно ередатьне только число, но и вообще какое угодно значение, то вначале мы пытаемся преобразовать это значение в число с помощью функции parseInt():
const age = parseInt(pAge);
if(isNaN(age)) throw new TypeError("Возраст должен представлять число");
Далее с помощью функции isNaN(age) проверяем, является полученное число числом. Если age — не число, то данная функция возвращает true. Поэтому генерируется ошибка типа TypeError.
Затем проверяем, что полученное число входит в допустимый диапазон. Если же не входит, генерируем ошибку типа RangeError:
if(age < 0 || age > 120) throw new RangeError("Возраст должен быть больше 0 и меньше 120");
Проверим генерацию исключений:
try{
const tom = new Person("Tom", -45);
}
catch(error){
// Возраст должен быть больше 0 и меньше 120
console.log(error.message);
}
try{
const bob = new Person("Bob", "bla bla");
}
catch(error){
// Возраст должен представлять число
console.log(error.message);
}
try{
const sam = new Person("Sam", 23);
// Name: Sam Age: 23
sam.print();
}
catch(error){
console.log(error.message);
}
Консольный вывод:
Возраст должен быть больше 0 и меньше 120
Возраст должен представлять число
Name: Sam Age: 23
Обработка нескольких типов ошибок
При выполнении одного и то же кода могут генерироваться ошибки разных типов. И иногда бывает необходимо разграничить обработку разных типов. В этом случае мы можем проверять тип возникшей ошибки. Например, пример выше с классом Person:
class Person{
constructor(pName, pAge){
const age = parseInt(pAge);
if(isNaN(age)) throw new TypeError("Возраст должен представлять число");
if(age < 0 || age > 120) throw new RangeError("Возраст должен быть больше 0 и меньше 120");
this.name = pName;
this.age = age;
}
print(){ console.log(`Name: ${this.name} Age: ${this.age}`);}
}
try{
const tom = new Person("Tom", -45);
const bob = new Person("Bob", "bla bla");
}
catch(error){
if (error instanceof TypeError) {
console.log("Некорректный тип данных.");
} else if (error instanceof RangeError) {
console.log("Недопустимое значение");
}
console.log(error.message);
}
Создание своих типов ошибок
Мы не ограничены встроенными только встроенными типами ошибок и при необходимости можем создавать свои типы ошибок, предназначеные для каких-то конкретных ситуаций:
class PersonError extends Error {
constructor(value, ...params) {
// остальные параметры передаем в конструктор базового класса
super(...params)
this.name = "PersonError"
this.argument = value;
}
}
class Person{
constructor(pName, pAge){
const age = parseInt(pAge);
if(isNaN(age)) throw new PersonError(pAge, "Возраст должен представлять число");
if(age < 0 || age > 120) throw new PersonError(pAge, "Возраст должен быть больше 0 и меньше 120");
this.name = pName;
this.age = age;
}
print(){ console.log(`Name: ${this.name} Age: ${this.age}`);}
}
try{
//const tom = new Person("Tom", -45);
const bob = new Person("Bob", "bla bla");
}
catch(error){
if (error instanceof PersonError) {
console.log("Ошибка типа Person. Некорректное значение:", error.argument);
}
console.log(error.message);
}
Консольный вывод:
Ошибка типа Person. Некорректное значение: bla bla
Возраст должен представлять число
Для представления ошибки класса Person здесь определен тип PersonError, который наследуется от класса Error:
class PersonError extends Error {
constructor(value, ...params) {
// остальные параметры передаем в конструктор базового класса
super(...params)
this.name = "PersonError"
this.argument = value;
}
}
В конструкторе мы определяем дополнительное свойство — argument. Оно будет хранить значение, которое вызвало ошибку. С помощью параметра value конструктора получаем это значение. Кроме того, переопреляем имя типа с помощью свойства this.name.
В классе Person используем этот тип, передавая в конструктор PersonError соответствующие значения:
if(isNaN(age)) throw new PersonError(pAge, "Возраст должен представлять число");
if(age < 0 || age > 120) throw new PersonError(pAge, "Возраст должен быть больше 0 и меньше 120");
Затем при обработки исключения мы можем проверить тип, и если он представляет класс PersonError, то обратиться к его свойству argument:
catch(error){
if (error instanceof PersonError) {
console.log("Ошибка типа Person. Некорректное значение:", error.argument);
}
console.log(error.message);
}