Замыкание — это функция, которая запоминает свои внешние переменные и может обращаться к ним. В Javascript все функции, естественно, являются замыканиями.

Есть три способа объявить переменную в Javascript:

let i = 1;
const j = 1;
var k = 1;

let и const ведут себя одинаково. После объявления со значением значение let или constvariable не может быть изменено снова в пределах одного и того же блока кода {…}. Если объявлено в кодовом блоке {…} , значение letили constvariable недоступно за пределами этого кодового блока.

let, объявленный в условиях для while, if и for, также считается объявленным в кодовом блоке. Например, к i в следующем примере нельзя получить доступ вне цикла for:

for (let i = 0; i < length; i++) {...}

Обратите внимание, что здесь нельзя использовать const.

Функции

Когда переменная let объявлена ​​во вложенной функции:

  1. При запуске каждой функции создается среда, в которой автоматически сохраняются локальные переменные и параметры вызова в момент его выполнения.
  2. Позже, если переменная изменится в какой-то момент в будущем, она изменится только в среде, в которой она живет.
  3. При поиске переменной 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.

Для циклов

  1. Для цикла for, который повторяет i, если i объявлено внутри условия, то новая переменная i создается в каждой итерации цикла, так что функции, объявленные внутри цикла, могут быть вызваны позже со значением i во время выполнения условия. объявление функции.
  2. Если 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 и решил проблему. После дальнейших чтений по теме закрытия родилась эта статья.