Для тех, кто не знаком с механизмом исключений в Java
Механизм исключений в JavaScript очень похож на механизм исключений в Java, так что если вы знакомы с последним, можете спокойно пропустить этот раздел и перейти к чтению следующего - в этом рассматриваются азы, общие для этих двух механизмов.
Исключение - это некий объект, который характеризует состояние системы в момент, когда произошла какая-то исключительная ситуация, т.е. в скрипте либо возникла ошибка, в силу чего стало невозможным его дальнейшее выполнение, либо в скрипте программист явно указал возбудить исключение при некоторых условиях при помощи соответствующей конструкции
throw. По сравнению со старыми языками, где в этой ситуации интерпретатор или скомпилированный код выдавали ошибки, современные языки сделали шаг вперёд, позволив программам самим реагироваать на исключения в себе - это повысило надёжность ПО и увеличило качество кода при написании сложных программ.По сути, на уровне кода обработка исключений очень похожа на обработку событий - если сопоставить объекту
Error объект event, то всё довольно быстро встанет на свои места - если код вызывает ошибку, происходит специфическое событие - исключение - его параметры записываются в специальный объект и он передаётся обработчику, который его обрабатывает.Для тех, кто знаком с механизмом исключений в Java
Здесь я кратко приведу различия между реализацией исключений в Java и JavaScript - пропустите этот раздел если с Java вы не знакомы.
Главное отличие от Java-реализации состоит в отсутствии (в силу не классовой, а прототипной реализации ООП) возможности использовать множественный оператор
catch, основанный на наследовании и восходящем преобразовании. Здесь оператор catch может быть только один для каждого try`я. Этот приём можно менее изящно реализовать в обработчике на основе оператора switch.Блок
finally присутствует, но здесь он нужен ещё реже. Сам я, работая с JavaScript, ни разу не сталкивался с ситуацией, где бы он мне понадобился или был удобен - поэтому здесь я о нём тихонько умолчу, только намекнув, что он, в принципе, здесь есть...Ну и, конечно, нет великолепной возможности (отсутствующей даже в C#) Java, обязывающей указывать возможность вызова исключения функцией при её описании с помощью ключевого слова
throws, отсутствие какового сулит обернуться большой путаницей при использовании больших сторонних библиотек...Объект исключения
Обычно в качестве объекта исключения выступает объект
Error, хотя, строго говоря, конструкция throw может передавать абсолютно любой объект (!), который может быть принят оператором catch и соответственно обработан.К сожалению, и область обработки исключительных ситуаций задела браузерная война - боевые действия в этой области привели к тому, что объекты
Error в ECMAScript и в JScript практически не имеют ничего общего.Какую информацию о состоянии может в себе нести исключение? По большому счёту всего 2 поля - некое название, характеризующие тип исключения, и сообщение, уточняющее особенности конкретного исключения в данном случае - если пользователь возбуждает исключение сам, то он придумывает сообщение сам, если его генерирует система - то уже она решает, какое сообщение писать. Прибавим к этим 2-м свойствам 3-е -
prototype, для возможности изменять его характеристики ОО-средствами и 4-е стандартное toString() - и получим объект исключения от ECMAScript, в котором название называется "name" (в случае пользовательских объектов оно содержит строку "Error", а в случае ошибки браузера - название из небольшого списка, представленного в следующей таблице), а строка сообщения - свойство "message". Конструктор исключения от ECMAScript выглядит так:new Error(message);У Microsoft вместо имени у ошибки появляется составной номер (свойство "number"), состоящий из кода источника ошибки (facility code) и номера самой ошибки. Что бы выделить номер источника, можно воспользоваться выражением (e.number >> 16) & 0x1FFF, а что бы выделить код самой ошибки - выражениемe.number & 0xFFFF, где e - объект Error), и "description", полностью аналогичное свойству "message" в ECMAScript (начиная с IE 5.5 значение свойства "description" доступно и через свойство "message", т.е. по существу, они - синонимы, ссылающиеся на одно и то же значение). Соответствие номеров описаниям для JScript можно найти в этой таблице.Конструктор объекта исключения от Microsoft IE выглядит так:
new Error(errorNumber, message);- этот формат не совместим с приведённым ранее форматом, соответственно, к сожалению, для различных браузеров придётся писать разные возбуждения исключений...Впрочем, популярный особенно в Linux-среде open-source`ный браузер Mozilla так же нередко расширяет стандарты (хотя существующие - поддерживает, в отличае от IE). В объекте
Error для этого браузера добавлено 2 интересных свойства для локализации исключения - "fileName" и "lineNumber", хранящие, соответственно, информацию о файле, где произошла ошибка (актуально, когда в проекте много *.js - файлов и непонятно в котором из них ошибка) и о номере строки в этом файле.Пример использования
Теперь давайте перейдём к практике. Для отлова исключений используется блок
try..catch, выглядит это примерно так:try {
оператор1
} catch (исключение) {
оператор2
}, где: оператор1 - оператор или их группа, где может быть вызвано исключение, оператор2 - обработчик исключения, исключение - обычно объект Error, характеризующий исключение и передаваемый оператору2.Отметим, что
оператор1 может включать вызовы функций - если в них возникнут исключения и там не окажется более глубоко вложенных блоков try..catch, внутри которых оно будет вызвано, то их поймает именно этот catch.Теперь о самостоятельном вызове с помощью оператора
throw. Как и в других темах, существует 2 способа писать универсальный код:- Различать браузеры и писать разный код для разных браузеров, и
- Писать более простой код, который относится к области пересечения браузеров.
Error из-за разного синтаксиса конструкторов и присваивать исключению простую строку:function getMonthName(month) {
month--; // Переводим month в индекс массива (1=январь, 12=декабрь)
var months=["январь","февраль","март","апрель","май","июнь","июль",
"август","сентябрь","октябрь","ноябрь","декабрь"];
if (months[month] != null)
return months[month];
else
throw "Неверный месяц";
}
try {
monthName = getMonthName(myMonth); // возможно исключение
} catch (e) {
monthName="неизвестно";
}
document.write(monthName);Ссылки по теме для более глубокого изучения:1) Ю.С. Лукач, "Справочник Web-разработчика", раздел "Обработка исключений";
2) Степанищев Евгений: Блоки try... catch... finally... в JScript 5. Статья на сайте CitForum.ru
P.S. Это одна из ранних моих статей, опубликованных на форуме программистов "Vingrad". Ознакомиться с комментариями Vingrad`цев можно тут.
