Конструкции языка. Обработка ошибок.
Раздел иллюстрирует особенности управляющих конструкций javascript, таких как while/for , switch и обработку исключений.
Две формы while:
// проверка вначале
while(i<5) { … }
// условие потом
do { … } while (i<5)
И две принципиально разные формы for . Одна - обычная:
// заметьте - новая переменная объявлена тут же
for (var i=0;i<10;i++) {
...
}
Другая - итерация по свойствам объекта:
for(key in obj) {
... obj[key]
}
Можно исключить унаследованные свойства (т.е исключить из цикла прототип). Для этого используем функцию hasOwnProperty :
// цикл только по собственным свойствам
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
… obj[key] …
}
}
В javascript можно использовать метки, чтобы прыгать между уровнями цикла.
Метки действуют только для циклов и switch , т.е организовать полноценный goto через них нельзя 
На метку внешнего цикла можно перейти при помощи break /continue , вот пример:
// внешний цикл
outer: for(…) {
…
// внутренний цикл
for (…) {
…
// можно вывалиться из внешнего цикла
break outer;
…
// или перейти на следующую итерацию внешнего цикла
continue outer;
…
}
}
В некоторых языках можно сделать только switch(число/строка) .
В javascript же конструкция switch принимает совершенно любой объект. Перед switch , как и перед циклами можно ставить метку, и делать break /continue на внешнюю метку.
switch (obj) {
case "test":
…
break
case 5:
…
break outer
default:
…
}
With - специфическая конструкция javascript, самый известный ее аналог - with в Pascal/Delphi. Поэтому мы остановимся на ней подольше.
У каждой функции есть своя область видимости. В простейшем случае, одна функция не видит внутренние переменные другой. Умение обращаться с областью видимости позволяет задавать приватные переменные класса, понимать и создавать замыкания , и многое другое.
Более подробно тема видимости разобрана в статье функции Javascript, а здесь - разберем конкретно то, что с ней делает with .
Коротко - with берет объект и делает из него новую вложенную область видимости.
Например, в некоторой функции:
function go() {
...
var obj
// obj будет браться из текущей области видимости
obj.size = 5
...
}
Создадим тестовый объект, но не просто var obj , а более развернуто:
(Более подробно об определении и свойствах объекта написано в разделе Объекты, ООП)
Если мы завернем любые операторы в блок with(obj) , то все свойства будут первым делом искаться в obj, а уже потом - во внешней области видимости.
В этом примере свойства weight и size будут взяты из объекта obj:
with (obj) {
// width/height берутся из найденного size
return weight / (size.width + size.height)
}
А здесь - with делает область видимости из obj.size :
with (obj.size) {
return width + height
}
В чем польза with? Как правило, его используют для упрощения синтаксиса, чтобы много раз не повторять объект.
Типичный пример из реальной жизни:
with (div.style) {
if (!browser.isSafari) {
position = 'absolute'
}
left = 0
right = 0
visibility = 'hidden'
}
Напомню, что интерпретатор javascript ищет все переменные в ближайшей области видимости. Если не находит - ищет в следующей, и так далее - до глобальных переменных, т.е window.
Поэтому можно, например, делать конструкции типа такой:
with (obj) {
with (size) {
return weight / (width + height)
}
}
Здесь переменные из разных областей видимости используются в одном выражении.
Область видимости size находится внутри obj , поэтому интерпретатор будет искать weight так:
- сначала посмотрит
weight в size
- не найдет там такой переменной
- посмотрит
weight в obj
- использует
weight из obj
Работа с with(obj) не эквивалентна работе напрямую с объектом obj , т.к никаких новых переменных добавить в obj нельзя.
Например, сделаем тестовый объект:
obj = {
weight: 100
}

Внутри with можно получить weight, и даже поменять его значение:

Но вот при попытке добавить переменную возникнет проблема:

Сам объект не поменялся, зато перезаписали глобальную переменную 
alert(obj.size) // => undefined
alert(window.size) // => 10
У with есть одна большая проблема, из-за которой многие вообще рекомендуют забыть эту конструкцию.
А именно - внутри блока with абсолютно нельзя сказать, откуда будет взята та или иная переменная.
Выше разобран пример, когда weight ищется сначала в size , затем в obj , и потом - в глобальной области window .
Если переменной не окажется там, где она по плану должна быть, то она будет взята/изменена в другой области видимости, возможно даже в глобальной window .
Это приводит к трудноуловимым ошибкам, поэтому часто используют альтернативу: временную переменную.

С другой стороны, синтаксис with удобнее и полезен там, где ошибок уж точно не может быть. Например, при манипуляции стилями.
Работа с исключениями в javascript организована в типичном для языка стиле вседозволенности.
Абсолютно любой объект можно бросить в виде исключения:
try {
...
throw {message: "Ого!"}
..
} catch (e) {
alert("Ага, попался!")
}
Обычно бросают, все же, не простые объекты, а потомки встроенного класса Error :
throw new Error("connection down, server timeout")
// или сделать наследника Error:
throw new ConnectionError("server timeout")
Встроенный класс Error удобен для унификации проверки "a instanceof Error " и интероперабельности с другими библиотеками, так как ничего полезного в нем часто нет.
В Firefox у объекта Error есть полный бэктрейс в свойстве stack и еще масса полезных свойств:
// так можно быстро узнать стек без отладчика
alert( (new Error()).stack )
В IE тоже есть некоторые полезные свойства, а в Opera/Safari - на момент написания только message :
var e = new Error("hi")
alert(e.message) // => "hi"
Поэтому, например, у меня созданы потомки (синтаксис фреймворка dojo):
// базовый класс для ошибок, со стеком (Firefox)
// сообщением message и дополнительной информацией extra
dojo.declare(
"dojo.Error",
Error,
function(message, extra) {
this.message = message;
this.extra = extra;
this.stack = (new Error()).stack;
}
)
// Потомок, имя ошибки хранится в name
// формат: dojo.declare(Имя, Родитель, Конструктор)
dojo.declare(
"dojo.CommunicationError",
dojo.Error,
function() {
this.name="CommunicationError";
}
)
// еще потомок для примера
dojo.declare(
"dojo.LockedError",
dojo.Error,
function() {
this.name="LockedError";
}
)
...
При перехвате исключений редко нужно перехватывать все подряд. Обычно - надо перехватить определенный класс исключений. Стандартный оператор catch такого не умеет, поэтому полный код обработки будет выглядить так:
try {
… код ...
} catch(e) {
// ловим нужное исключение
if (e instanceof ConnectionError) {
// обрабатываем его
… reconnect …
} else {
// пробрасываем незнакомое исключение дальше
throw e
}
} finally {
// блок finally выполняется всегда,
// вне зависимости - было исключение или нет
… notifyUser() ..
}
В этом примере также присутствует блок finally , взятый в javascript из java. В стандартной схеме try..catch..finally, код из блока finally выполняется либо после try , если эксепшна нет, либо после catch , даже если эксепшн выпал наружу.
Короче говоря, код в finally выполнится при любом результате работы try/catch , и туда удобно ставить всякие очистки, уведомления о конце процесса и т.п.
|
ทางเข้าufabet168 เว็บตรง เสถียร ใช้งานง่ายที่สุด
You can also download latest APKs, like Zaxiusdomain
You can also download these injectors to enhance your MLBB game experience.
Great post! I am actually getting ready to across this information, is very helpful my friend. I also like to recommend a site that is all about buy telegram members. Keep up the good work you are doing here. betflixvip
인천오피
I am really enjoying reading your well written articles. It looks like you spend a lot of effort and time on your blog. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work.
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.