Замыкание — это функция, которая запоминает свои внешние переменные и может обращаться к ним. В Javascript все функции, естественно, являются замыканиями.
Есть три способа объявить переменную в Javascript:
let i = 1; const j = 1; var k = 1;
let
и const
ведут себя одинаково. После объявления со значением значение let
или const
variable не может быть изменено снова в пределах одного и того же блока кода {…}
. Если объявлено в кодовом блоке {…}
, значение let
или const
variable недоступно за пределами этого кодового блока.
let
, объявленный в условиях для while
, if
и for
, также считается объявленным в кодовом блоке. Например, к i
в следующем примере нельзя получить доступ вне цикла for:
for (let i = 0; i < length; i++) {...}
Обратите внимание, что здесь нельзя использовать const
.
Функции
Когда переменная let
объявлена во вложенной функции:
- При запуске каждой функции создается среда, в которой автоматически сохраняются локальные переменные и параметры вызова в момент его выполнения.
- Позже, если переменная изменится в какой-то момент в будущем, она изменится только в среде, в которой она живет.
- При поиске переменной Javascript начнет с блока кода, вызывающего эту переменную, а затем с внешнего, вплоть до глобального окружения. Он останавливает поиск, как только находит его. Если он не может найти переменную нигде, даже в глобальной среде, он покажет сообщение об ошибке или создаст новую глобальную переменную.
Вот пример из этого источника обучения:
let count = 1; function makeCounter1() { let count = 0; return function () { return count++; }; } let check1 = makeCounter1(); check1(); // return 0, because it cannot find conut inside function(), it goes up a level to find count = 0; It returns count = 0 and add 1 to count. Now count = 1 in the makeCounter1() environment. check1(); // return 1, because it cannot find count inside function(), it goes up a level to find count = 1 in the makeCounter1() environment. It returns count = 1 and add 1 to count. Now count = 2 in the makeCounter1() environment. check1(); // return 2
Если мы удалим let count = 0
из makeCounter():
let count = 1; function makeCounter2() { return function () { return count++; }; } let check2 = makeCounter2(); check2(); // return 1, because it cannot find count inside function() or makeCounter2(), it searches the global environment.
Для циклов
- Для цикла for, который повторяет
i
, еслиi
объявлено внутри условия, то новая переменнаяi
создается в каждой итерации цикла, так что функции, объявленные внутри цикла, могут быть вызваны позже со значениемi
во время выполнения условия. объявление функции. - Если
i
объявлено вне цикла for, то функции, объявленные внутри цикла, сохраняют только ссылкуi
. Когда функции вызываются позже, он может получить доступ только к значениюi
во время вызова функции.
Вот пример:
const list = []; for (let j = 0; j < 3; j++) { list.push(() => j); } list[0](); // return 0 list[1](); // return 1 list[2](); // return 2
Если j
объявлен снаружи:
const list = []; let j; for (j = 0; j < 3; j++) { list.push(() => j); } list[0](); // return 3, because j is only a reference at the time of function creation. By the time the function is called, j is already 3. list[1](); // return 3 list[2](); // return 3
Вышеупомянутое поведение существует не только в Javascript, но и в Python.
Обучаюсь веб-разработке в Recurse Center. На прошлой неделе я несколько часов застрял в своем проекте почтового клиента, прежде чем мой коллега по рекурсии показал мне различные примеры закрытия в Javascript и решил проблему. После дальнейших чтений по теме закрытия родилась эта статья.