You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
One of JavaScript's most powerful features is the availability of *closures*,
4
-
this means that scopes **always** keep access to the outer scope they were
5
-
defined in. Since the only scoping that JavaScript has is
6
-
[function scope](#function.scopes), all functions, by default, act as closures.
3
+
Одним из самых мощных инструментов JavaScript'а считаются возмжность создавать *замыкания* — это когда наша область видимости **всегда** имеет доступ к внешней области, в которой она была объявлена. Собственно, единственный механизм работы с областями видимости в JavaScript — это [функции](#function.scopes): т.е. объявляя функцию, вы автоматически реализуете замыкания.
7
4
8
-
### Emulating private variables
5
+
### Эмуляция приватных свойств
9
6
10
7
function Counter(start) {
11
8
var count = start;
@@ -24,69 +21,52 @@ defined in. Since the only scoping that JavaScript has is
24
21
foo.increment();
25
22
foo.get(); // 5
26
23
27
-
Here, `Counter` returns **two** closures. The function `increment` as well as
28
-
the function `get`. Both of these functions keep a **reference** to the scope of
29
-
`Counter` and, therefore, always keep access to the `count` variable that was
30
-
defined in that very scope.
24
+
В данном примере `Counter` возвращает **два** замыкания: функции `increment` и `get`. Обе эти функции сохраняют **ссылку** на область видимости `Counter` и, соответственно, имеют доступ к переменной `count` из этой самой области.
31
25
32
-
### Why private variables work
26
+
### Как это работает
33
27
34
-
Since it is not possible to reference or assign scopes in JavaScript, there is
35
-
**no** way of accessing the variable `count` from the outside. The only way to
36
-
interact with it is via the two closures.
28
+
Поскольку в JavaScript нельзя присваивать или ссылаться на области видимости, заполучить `count` извне **не** представляется возможным. Единственным способом взаимодействовать с ним остается использование двух замыканий.
37
29
38
30
var foo = new Counter(4);
39
31
foo.hack = function() {
40
32
count = 1337;
41
33
};
42
34
43
-
The above code will **not** change the variable `count` in the scope of `Counter`,
44
-
since `foo.hack` was not defined in **that** scope. It will instead create - or
45
-
override - the *global* variable `count`.
35
+
В приведенном примере мы **не** изменяем переменную `count` в области видимости `Counter`, т.к. `foo.hack` не объявлен в **данной** области. Вместо этого будет создана или перезаписана *глобальная* переменная `count`;
46
36
47
-
### Closures inside loops
37
+
### Замыкания внутри циклов
48
38
49
-
One often made mistake is to use closures inside of loops, as if they were
50
-
copying the value of the loops index variable.
39
+
Часто встречается ошибка, когда замыкания используют внутри циклов, передавая переменную индекса внутрь.
51
40
52
41
for(var i = 0; i < 10; i++) {
53
42
setTimeout(function() {
54
-
console.log(i);
43
+
console.log(i);
55
44
}, 1000);
56
45
}
57
46
58
-
The above will **not** output the numbers `0` through `9`, but will simply print
59
-
the number `10` ten times.
47
+
Данный код **не** будет выводить числа с `0` до `9`, вместо этого число `10` будет выведено десять раз.
60
48
61
-
The *anonymous* function keeps a **reference** to `i` and at the time
62
-
`console.log` gets called, the `for loop` has already finished and the value of
63
-
`i` as been set to `10`.
49
+
*Анонимная* функция сохраняет **ссылку** на `i` и когда будет вызвана функция `console.log`, цикл `for` уже закончит свою работу, а в `i` будет содержаться `10`.
64
50
65
-
In order to get the desired behavior, it is necessary to create a **copy** of
66
-
the value of `i`.
51
+
Для получения желаемого результата необходимо создать **копию** переменной `i`.
67
52
68
-
### Avoiding the reference problem
53
+
### Во избежание ошибок
69
54
70
-
In order to copy the value of the loop's index variable, it is best to use an
71
-
[anonymous wrapper](#function.scopes).
55
+
Для того, чтобы скопировать значение индекса из цикла, лучше всего использовать [анонимную функцию](#function.scopes) как обёртку.
72
56
73
57
for(var i = 0; i < 10; i++) {
74
58
(function(e) {
75
59
setTimeout(function() {
76
-
console.log(e);
60
+
console.log(e);
77
61
}, 1000);
78
62
})(i);
79
63
}
80
64
81
-
The anonymous outer function gets called immediately with `i` as its first
82
-
argument and will receive a copy of the **value** of `i` as its parameter `e`.
65
+
Анонимная функция-обертка будет вызвана сразу же, и в качестве первого аргумента получит `i`, **значение** которой будет скопировано в параметр `e`.
83
66
84
-
The anonymous function that gets passed to `setTimeout` now has a reference to
85
-
`e`, whose value does **not** get changed by the loop.
67
+
Анонимная функция, которая передается в `setTimeout`, теперь содержит ссылку на `e`, значение которой **не** изменяется циклом.
86
68
87
-
There is another possible way of achieving this; that is to return a function
88
-
from the anonymous wrapper, that will then have the same behavior as the code
89
-
above.
69
+
Еще одним способом реализации является возврат функции из анонимной функции-обертки, поведение этого кода будет таким же, как и в коде из предыдущего примера.
90
70
91
71
for(var i = 0; i < 10; i++) {
92
72
setTimeout((function(e) {
@@ -96,3 +76,5 @@ above.
96
76
})(i), 1000)
97
77
}
98
78
79
+
> **Замечание** от перев. Переменную `e` можно тоже назвать `i`, если вы хотите: это не поменяет поведения кода — внутренняя переменная `i` всё также будет *копией* внешней переменной
0 commit comments