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

>  context = newContext;

>  var result = body();

>  context = oldContext;

>  return result;

>}

Что, если функция >body выбросит исключение? В таком случае вызов >withContext будет выброшен исключением из стека, и переменной >context никогда не будет возвращено первоначальное значение.

Но у инструкции >try есть ещё одна особенность. За ней может следовать блок >finally, либо вместо >catch, либо вместе с >catch. Блок >finally означает «выполнить код в любом случае после выполнения блока >try». Если функции надо что-то подчистить, то подчищающий код нужно включать в блок >finally.

>function withContext(newContext, body) {

>  var oldContext = context;

>  context = newContext;

>  try {

>    return body();

>  } finally {

>    context = oldContext;

>  }

>}

Заметьте, что нам больше не нужно сохранять результат вызова >body в отдельной переменной, чтобы вернуть его. Даже если мы возвращаемся из блока >try, блок >finally всё равно будет выполнен. Теперь мы можем безопасно сделать так:

>try {

>  withContext(5, function() {

>    if (context < 10)

>      throw new Error("Контекст слишком мал!");

>  });

>} catch (e) {

>  console.log("Игнорируем: " + e);

>}

>// → Игнорируем: Error: Контекст слишком мал!


>console.log(context);

>// → null

Несмотря на то, что вызываемая из >withContext функция «сломалась», сам по себе >withContext по-прежнему подчищает значение переменной >context.

Выборочный отлов исключений

Когда исключение доходит до низа стека и его никто не поймал, его обрабатывает окружение. Как именно – зависит от конкретного окружения. В браузерах описание ошибки выдаётся в консоль (она обычно доступна в меню «Инструменты» или «Разработка»).

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

Если возникновение проблемы предсказуемо, программа не должна падать с необработанным исключением – это не очень дружественно по отношению к пользователю.

Недопустимое использование языка – ссылки на несуществующую переменную, запрос свойств у переменной, равной >null, или вызов чего-то, что не является функцией – тоже приводит к выбрасыванию исключений. Такие исключения можно отлавливать точно так же, как свои собственные.

При входе в блок >catch мы знаем только, что что-то внутри блока >try привело к исключению. Мы не знаем, что именно, и какое исключение произошло.