В блоке 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){ console.log(error.name); // TypeError console.log(error.message); // Assignment to constant variable. }
При генерации ошибок мы можем использовать встроенные типы ошибок. Например:
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){ console.log(error.message); // Возраст должен быть больше 0 и меньше 120 } try{ const bob = new Person("Bob", "bla bla"); } catch(error){ console.log(error.message); // Возраст должен представлять число } try{ const sam = new Person("Sam", 23); sam.print(); // Name: Sam Age: 23 } 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); }