JavaScript

Как работает замыкание в js

 function createCounter() { 
let counter =0;
counter = counter - 10
const myFunction = function () {
counter = counter+1;
return counter
}
return myFunction
}
let z = createCounter()

console.log(z())
createCounter()
console.log(z())
Подскажите почему при последнем вызове console.log(z()) мы получаем (-8), а не (-9)
Первый вызов console.log(z()) нам дает let counter =0; далее (counter - 10 ) получаем (-10) далее
counter = (-10) + 1 =(-9); но ведь потом мы вызываем createCounter() и снова let counter =0; и при вызове console.log(z()) у нас let counter =0; почему мы тогда получаем (-8), а не (-9) где я допускаю ошибку
Подскажите почему так происходит и как работает данный код ?
При каждом вызове createCounter создаётся новая переменная counter, равная 0, и новый экземпляр функции-замыкания, который "захватывает" эту новую counter.

При этом созданная на предыдущем вызове counter никак не меняется. И новые вызовы createCounter никак не могут повлиять на замыкание, присвоенное переменной z.

P.S. createCounter - фабрика, которая выпускает изделия-замыкания, никак не связанные другом с другом.
Николай Завьялов
Николай Завьялов
95 370
Лучший ответ
 function () {  
counter = counter+1;
return counter
}
При вызове z = createCounter(), в переменную `z` попадает эта функция. Сколько не вызывай createCounter(), он будет создавать новый счетчик и возвращать новую функцию, которая начинала бы отсчет заново, но новая созданная функция нигде не сохраняется, а переменная `z` так же не меняется и продолжает свой отсчет.

Если присвоить новый createCounter() в переменную `z`, будет
 console.log(z()) // -9
z = createCounter()
console.log(z()) // -9
Или, если хочется уметь влиять на counter извне, можно сделать для этого отдельный метод:
 function createCounter(initValue) {  
let counter = initValue || 0;

function myFunction() {
counter = counter + 1;
return counter;
}

myFunction.set = function(value) {
counter = value;
};

return myFunction;
}

let z = createCounter(-10);

console.log(z()); // -9
z.set(0)
console.log(z()); // 1
Для этого есть более современный и правильный вариант, через class...
Но пока код маленький, и так сойдет)
A&
Asko """"
62 361
Дмитрий Ларионов а откуда при повторном вызове console.log(z()) будет браться counter из этой фунукии
 function () {   
counter = counter+1;
return counter
}
или из внешней
Замыкание в данном коде работает так: функция createCounter() возвращает внутреннюю функцию myFunction(). При каждом вызове createCounter() создается свое лексическое окружение, включающее переменную counter, которая инициализируется значением 0 и уменьшается на 10. Затем внутри myFunction() к этой переменной добавляется 1 при каждом вызове функции.

Когда мы вызываем z() первый раз, мы получаем значение равное 1, так как мы изначально уменьшили переменную counter на 10 и затем увеличили ее на 1.

Когда мы вызываем createCounter() второй раз, мы создаем новое лексическое окружение и новую переменную counter со значением 0.

Но когда мы вызываем z() второй раз, мы получаем значение 2, а не 0 или 1. Это происходит потому, что замыкание сохраняет значение переменной counter внутри функции myFunction() между вызовами, то есть, когда мы вызываем createCounter() второй раз, сохраненное значение counter внутри myFunction() все еще равно -9.

Поэтому когда мы вызываем z() второй раз, мы увеличиваем сохраненное значение counter на 1 и получаем -8 вместо -9.
Леонид Л
Леонид Л
59 846
Дмитрий Ларионов Когда мы вызываем z() первый раз, мы получаем значение равное 1, так как мы изначально уменьшили переменную counter на 10 и затем увеличили ее на 1.Так вроде получаем(-9) а не 1 ?
Леонид Л ага -9. чертовы, недоделаные, нейросети посчитать нормально не могут ((
 function createCounter() { 
let counter = -10;
return function () {
return ++counter;
}
}
const z = createCounter();
const y = createCounter();

console.log(z()); // -9
console.log(z()); // -8
console.log(y()); // -9
console.log(y()); // -8
Упростил немного твой код.
Функции z и y имеют собственный counter, независимый друг от друга. Каждый последующий вызов createCounter создаёт свою версию counter и не влияет на остальные.
Сергей Архипов
Сергей Архипов
23 960