Выразительный JavaScript (Хавербеке) - страница 88

JavaScript (что является вопиющим упущением) не предоставляет непосредственной поддержки выборочного отлова исключений: либо ловим все, либо никакие. Из-за этого люди часто предполагают, что случившееся исключение – именно то, ради которого и писался блок >catch.

Но может быть и по-другому. Нарушение произошло где-то ещё, или в программу вкралась ошибка. Вот пример, где мы пробуем вызывать >promptDirection до тех пор, пока не получим допустимый ответ:

>for (;;) {

>  try {

>    var dir = promtDirection("Куда?"); // ← опечатка!

>    console.log("Ваш выбор", dir);

>    break;

>  } catch (e) {

>    console.log("Недопустимое направление. Попробуйте ещё раз.");

>  }

>}

Конструкция >for (;;) – способ устроить бесконечный цикл. Мы вываливаемся из него, только когда получаем допустимое направление. Но мы неправильно написали название >promptDirection, что приводит к ошибке “undefined variable”. А так как блок >catch игнорирует значение исключения >e, предполагая, что он разбирается с другой проблемой, он считает, что выброшенное исключение является результатом неправильных входных данных. Это приводит к бесконечному циклу и скрывает полезное сообщение об ошибке насчёт неправильного имени переменной.

Как правило, не стоит так ловить исключения, если только у вас нет цели перенаправить их куда-либо – к примеру, по сети, чтобы сообщить другой системе о падении нашей программы. И даже тогда внимательно смотрите, не будет ли скрыта важная информация.

Значит, нам надо поймать определённое исключение. Мы можем в блоке >catch проверять, является ли случившееся исключение интересующим нас исключением, а в противном случае заново выбрасывать его. Но как нам распознать исключение?

Конечно, мы могли бы сравнить свойство >message с сообщением об ошибке, которую мы ждём. Но это ненадёжный способ писать код – использовать информацию, предназначающуюся для человека (сообщение), чтобы принять программное решение. Как только кто-нибудь поменяет или переведёт это сообщение, код перестанет работать.

Давайте лучше определим новый тип ошибки и используем >instanceof для его распознавания.

>function InputError(message) {

>  this.message = message;

>  this.stack = (new Error()).stack;

>}

>InputError.prototype = Object.create(Error.prototype);

>InputError.prototype.name = "InputError";

Прототип наследуется от >Error.prototype, поэтому >instanceof Error тоже будет выполняться для объектов типа >InputError. И ему назначено свойство >name, как и другим стандартным типам ошибок (>Error, >SyntaxError, >ReferenceError, и т. п.)

Присвоение свойству