Типы ошибок
В блоке 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);
}