Конструкция with позволяет использовать в качестве области видимости для переменных произвольный объект.
В современном JavaScript от этой конструкции отказались. С use strict она не работает, но её ещё можно найти в старом коде, так что стоит познакомиться с ней, чтобы если что – понимать, о чём речь.
Синтаксис:
with(obj) {
...код...
}
Любое обращение к переменной внутри with сначала ищет её среди свойств obj, а только потом – вне with.
Пример
В примере ниже переменная будет взята не из глобальной области, а из obj:
Попробуем получить переменную, которой в obj нет:
Здесь интерпретатор сначала проверяет наличие obj.b, не находит и идёт вне with.
Особенно забавно выглядит применение вложенных with:
Свойства из разных объектов используются как обычные переменные... Магия! Порядок поиска переменных в выделенном коде: size => obj => window.
Изменения переменной
При использовании with, как и во вложенных функциях – переменная изменяется в той области, где была найдена.
Например:
Почему отказались от with?
Есть несколько причин.
-
В современном стандарте
JavaScriptотказались отwith, потому что конструкцияwithподвержена ошибкам и непрозрачна.Проблемы возникают в том случае, когда в
with(obj)присваивается переменная, которая по замыслу должна быть в свойствахobj, но её там нет.Например:
В строке
(2)присваивается свойство, отсутствующее вobj. В результате интерпретатор, не найдя его, создаёт новую глобальную переменнуюwindow.size.Такие ошибки редки, но очень сложны в отладке, особенно если
sizeизменилась не вwindow, а где-нибудь во внешнемLexicalEnvironment. -
Ещё одна причина – алгоритмы сжатия JavaScript не любят
with. Перед выкладкой на сервер JavaScript сжимают. Для этого есть много инструментов, например Closure Compiler и UglifyJS. Обычно они переименовывают локальные переменные в более короткие имена, но не свойства объектов. С конструкциейwithдо запуска кода непонятно – откуда будет взята переменная. Поэтому выходит, что, на всякий случай (если это свойство), лучше её не переименовывать. Таким образом, качество сжатия кода страдает. -
Ну и, наконец, производительность – усложнение поиска переменной из-за
withвлечёт дополнительные накладные расходы.Современные движки применяют много внутренних оптимизаций, ряд которых не может быть применён к коду, в котором есть
with.Вот, к примеру, запустите этот код в современном браузере. Производительность функции
fastсущественно отличается отslowс пустым(!)with. И дело тут именно вwith, т.к. наличие этой конструкции препятствует оптимизации.
Замена with
Вместо with рекомендуется использовать временную переменную, например:
/* вместо
with(elem.style) {
top = '10px';
left = '20px';
}
*/
var s = elem.style;
s.top = '10px';
s.left = '0';
Это не так элегантно, но убирает лишний уровень вложенности и абсолютно точно понятно, что будет происходить и куда присвоятся свойства.
Итого
- Конструкция
with(obj) { ... }используетobjкак дополнительную область видимости. Все переменные, к которым идёт обращение внутри блока, сначала ищутся вobj. - Конструкция
withустарела и не рекомендуется по ряду причин. Избегайте её.
Комментарии
<code>, для нескольких строк кода — тег<pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen...)