Для тех, кто не знаком с механизмом исключений в 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`цев можно тут.
Комментариев нет:
Отправить комментарий