init
This commit is contained in:
parent
06f61d8ce8
commit
f301cb744d
2271 changed files with 103162 additions and 0 deletions
|
@ -0,0 +1,17 @@
|
|||
Вторая (`2`), т.к. при обращении к любой переменной внутри `with` -- она ищется прежде всего в объекте.
|
||||
|
||||
Соответственно, будет выведено `2`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function f() { alert(1) }
|
||||
|
||||
var obj = {
|
||||
f: function() { alert(2) }
|
||||
};
|
||||
|
||||
with(obj) {
|
||||
f();
|
||||
}
|
||||
```
|
||||
|
18
01-js/05-functions-closures/07-with/01-with-function/task.md
Normal file
18
01-js/05-functions-closures/07-with/01-with-function/task.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
# With + функция
|
||||
|
||||
[importance 5]
|
||||
|
||||
Какая из функций будет вызвана?
|
||||
|
||||
```js
|
||||
function f() { alert(1) }
|
||||
|
||||
var obj = {
|
||||
f: function() { alert(2) }
|
||||
};
|
||||
|
||||
with(obj) {
|
||||
f();
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
Выведет `3`.
|
||||
|
||||
**Конструкция `with` не создаёт области видимости,** её создают только функции. Поэтому объявление `var b` внутри конструкции работает также, как если бы оно было вне её.
|
||||
|
||||
Код в задаче эквивалентен такому:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var a = 1;
|
||||
*!*
|
||||
var b;
|
||||
*/!*
|
||||
|
||||
var obj = { b: 2 }
|
||||
|
||||
with(obj) {
|
||||
alert( a + b );
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# With + переменные
|
||||
|
||||
[importance 5]
|
||||
|
||||
Что выведет этот код?
|
||||
|
||||
```js
|
||||
var a = 1;
|
||||
|
||||
var obj = { b: 2 };
|
||||
|
||||
with(obj) {
|
||||
var b;
|
||||
alert( a + b );
|
||||
}
|
||||
```
|
||||
|
181
01-js/05-functions-closures/07-with/article.md
Normal file
181
01-js/05-functions-closures/07-with/article.md
Normal file
|
@ -0,0 +1,181 @@
|
|||
# Устаревшая конструкция "with"
|
||||
|
||||
Конструкция `with` позволяет использовать в качестве области видимости для переменных произвольный объект.
|
||||
|
||||
В современном JavaScript от этой конструкции отказались. С `use strict` она не работает, но её ещё можно найти в старом коде, так что стоит познакомиться с ней, чтобы если что -- понимать, о чём речь.
|
||||
|
||||
[cut]
|
||||
Синтаксис:
|
||||
|
||||
```js
|
||||
with(obj) {
|
||||
... код ...
|
||||
}
|
||||
```
|
||||
|
||||
**Любое обращение к переменной внутри `with` сначала ищет её среди свойств `obj`, а только потом -- вне `with`.**
|
||||
|
||||
## Пример
|
||||
|
||||
В примере ниже переменная будет взята не из глобальной области, а из `obj`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var a = 5;
|
||||
|
||||
var obj = { a : 10 };
|
||||
|
||||
*!*
|
||||
with(obj) {
|
||||
alert(a); // 10, из obj
|
||||
}
|
||||
*/!*
|
||||
```
|
||||
|
||||
Попробуем получить переменную, которой в `obj` нет:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var b = 1;
|
||||
|
||||
var obj = { a : 10 };
|
||||
|
||||
*!*
|
||||
with(obj) {
|
||||
alert(b); // 1, из window
|
||||
}
|
||||
*/!*
|
||||
```
|
||||
|
||||
Здесь интерпретатор сначала проверяет наличие `obj.b`, не находит и идет вне `with`.
|
||||
|
||||
Особенно забавно выглядит применение вложенных `with`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var obj = {
|
||||
weight: 10,
|
||||
size: {
|
||||
width: 5,
|
||||
height: 7
|
||||
}
|
||||
};
|
||||
|
||||
with(obj) {
|
||||
with(size) { // size будет взят из obj
|
||||
*!*
|
||||
alert( width*height / weight ); // width,height из size, weight из obj
|
||||
*/!*
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Свойства из разных объектов используются как обычные переменные... Магия! Порядок поиска переменных в выделенном коде: `size => obj => window`
|
||||
|
||||
<img src="with_obj_size.png">
|
||||
|
||||
## Изменения переменной
|
||||
|
||||
При использовании `with`, как и во вложенных функциях -- переменная изменяется в той области, где была найдена.
|
||||
|
||||
Например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var obj = { a : 10 }
|
||||
|
||||
*!*
|
||||
with(obj) {
|
||||
a = 20;
|
||||
}
|
||||
*/!*
|
||||
alert(obj.a); // 20, переменная была изменена в объекте
|
||||
```
|
||||
|
||||
## Почему отказались от with?
|
||||
|
||||
Есть несколько причин.
|
||||
|
||||
<ol>
|
||||
<li>В современном стандарте `JavaScript` отказались от `with`, потому что **конструкция `with` подвержена ошибкам и непрозрачна.**
|
||||
|
||||
Проблемы возникают в том случае, когда в `with(obj)` присваивается переменная, которая по замыслу должна быть в свойствах `obj`, но ее там нет.
|
||||
|
||||
Например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var obj = { weight: 10 };
|
||||
|
||||
with(obj) {
|
||||
weight = 20; // (1)
|
||||
size = 35; // (2)
|
||||
}
|
||||
|
||||
alert(obj.size);
|
||||
alert(window.size);
|
||||
```
|
||||
|
||||
В строке `(2)` присваивается свойство, отсутствующее в `obj`. В результате интерпретатор, не найдя его, создает новую глобальную переменную `window.size`.
|
||||
|
||||
Такие ошибки редки, но очень сложны в отладке, особенно если `size` изменилась не в `window`, а где-нибудь во внешнем `LexicalEnvironment`.
|
||||
</li>
|
||||
<li>Еще одна причина -- **алгоритмы сжатия JavaScript не любят `with`**. Перед выкладкой на сервер JavaScript сжимают. Для этого есть много инструментов, например [Closure Compiler](http://code.google.com/intl/ru-RU/closure/compiler/) и [UglifyJS](https://github.com/mishoo/UglifyJS). Если вкратце -- они либо сжимают код с `with` с ошибками, либо оставляют его частично несжатым.</li>
|
||||
<li>Ну и, наконец, **производительность -- усложнение поиска переменной из-за `with` влечет дополнительные накладные расходы**. Современные движки применяют много внутренних оптимизаций, ряд которых не могут быть применены к коду, в котором есть `with`.
|
||||
|
||||
Вот, к примеру, запустите этот код в современном браузере. Производительность функции `fast` существенно отличается `slow` с пустым(!) `with`. И дело тут именно в `with`, т.к. наличие этой конструкции препятствует оптимизации.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var i = 0;
|
||||
|
||||
function fast() {
|
||||
i++;
|
||||
}
|
||||
|
||||
function slow() {
|
||||
with(i) {}
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
var time = new Date();
|
||||
while(i < 1000000) fast();
|
||||
alert(new Date - time);
|
||||
|
||||
var time = new Date();
|
||||
i=0;
|
||||
while(i < 1000000) slow();
|
||||
alert(new Date - time);
|
||||
```
|
||||
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
### Замена with
|
||||
|
||||
Вместо `with` рекомендуется использовать временную переменную, например:
|
||||
|
||||
```js
|
||||
/* вместо
|
||||
with(elem.style) {
|
||||
top = '10px';
|
||||
left = '20px';
|
||||
}
|
||||
*/
|
||||
|
||||
var s = elem.style;
|
||||
|
||||
s.top = '10px';
|
||||
s.left = '0';
|
||||
```
|
||||
|
||||
Это не так элегантно, но убирает лишний уровень вложенности и абсолютно точно понятно, что будет происходить и куда присвоятся свойства.
|
||||
|
||||
## Итого
|
||||
|
||||
<ul>
|
||||
<li>Конструкция `with(obj) { ... }` использует `obj` как дополнительную область видимости. Все переменные, к которым идет обращение внутри блока, сначала ищутся в `obj`.</li>
|
||||
<li>Конструкция `with` устарела и не рекомендуется по ряду причин. Избегайте её.</li>
|
||||
</ul>
|
||||
|
BIN
01-js/05-functions-closures/07-with/with_obj_size.png
Executable file
BIN
01-js/05-functions-closures/07-with/with_obj_size.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
Loading…
Add table
Add a link
Reference in a new issue