Ошибка смешения JavaScript
→ jsFiddle
function f1(){
var n=999;
nAdd=function(){n+=1;};
function f2(){
alert(n);
}
return f2;
}
var result = f1();
var result2 = f1();
result(); // 999
nAdd();
result2(); // 1000
result2(); // 1000
result(); // 999
Я пытаюсь изучить закрытие JavaScript, но приведенный выше код просто запутал меня.
Когда вызывается первый раз result()
, это 999. Это нормально для меня.
После вызова nAdd()
result2()
показывает 1000. И я думаю, что это связано с функцией result2()
, а функция result()
равна функции f1()
.
Но почему последний result()
показывает 999 вместо 1000?
Ответы
Ответ 1
Каждый раз, когда вызывается f1()
, который создает новое замыкание со своей локальной переменной n
.
Однако переменная nAdd
является глобальной и поэтому перезаписывается каждый раз, когда вызывается f1()
, что означает, что вызов nAdd()
будет только добавлять к переменной n
в последнем закрытии.
UPDATE: если вы хотите иметь возможность увеличивать значения n
в каждом закрытии независимо, вы можете сделать что-то вроде этого:
function f1(){
var n=999;
return {
incrementN : function(){n+=1;},
getN : function f2(){console.log(n);}
}
}
var result = f1();
var result2 = f1();
result.getN(); // 999
result.incrementN();
result2.getN();//999
result2.incrementN();
result2.getN();//1000
result.getN();//1000
То есть, f1()
возвращает объект, содержащий два метода, которые не объявлены как глобальные, и что они работают с локальной переменной n
из замыкания, к которому они принадлежат.
Ответ 2
Уже есть хорошие ответы, но я думаю, что картина будет полезна для понимания.
![enter image description here]()
Ответ 3
Каждый раз, когда вы вызываете f1()
, вы:
- Создайте новую (локальную) переменную с именем
n
со значением 999
- Создайте новую безымянную функцию, назначенную глобальной
nAdd
, которая изменяет это n
(и перезаписывает любую предыдущую функцию, назначенную nAdd
)
- Создайте новую функцию, которую вы возвращаете, которая оповещает значение этого
n
Вы дважды вызываете f1()
, поэтому вы делаете все это дважды. Во второй раз, когда вы его вызываете, вы перезаписываете nAdd
новой функцией, которая изменяет вторую n
.
Это дает вам:
-
result()
, который предупреждает первый n
-
result2()
, который предупреждает второй n
-
nAdd()
, который увеличивает второй n
result()
в последней строке оповещает 999
, потому что он предупреждает о значении первого n
(который никогда не увеличивался).
Ответ 4
result
и result2
содержат результат различных вызовов f1
и, следовательно, содержат разные экземпляры локальной переменной n
. Каждый вызов функции может иметь разные значения для локальных переменных этой функции. Это применяется даже тогда, когда не задействованы блокировки.
Ответ 5
Строка nAdd=function(){n+=1;};
создает глобальную функцию, которая является замыканием внутри f1()
. Закрытие также имеет доступ ко всем переменным из области действия созданной им функции. Поэтому каждый раз, когда вы вызываете f1()
, он создает новую функцию nAdd()
, которая имеет значение n
, связанное со значением var n
вызова f1()
.
В вашем коде
var result = f1();
var result2 = f1();
result(); // 999
nAdd(); // Created by "var result2 = f1();" and has the same 'n' value as function in result2
result2();//1000
result2();//1000
result();//999
Ответ 6
результат и результат2 создают два разных замыкания с разными n. Если вы сделаете n глобальной переменной, объявив ее вне функции f1(), вы получите ожидаемый результат, так как в этом случае вы всегда будете обращаться к глобальной переменной n:
var n = 999; функция f1() { Надд = функция() {п + = 1;};
функция f2() { console.log(п);
}
return f2;
}
var result = f1();
var result2 = f1();
результат (а);//999
Надд();
result2();//1000
result2();//1000
результат (а);//1000
Ответ 7
вот так:
var nAdd;
function f1(){
var n=999;
nAdd=function(){n+=1;};
function f2(){
alert(n);
}
return f2;
}
var result = f1();//var nAdd=function(){n+=1;} n=result.n=999
var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999
var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999
nAdd();
result(); // 999
result2(); // 999
result3(); // 1000
var result = f1();//var nAdd=function(){n+=1;} n=result.n=999
var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999
nAdd();
var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999
result(); // 999
result2(); // 1000
result3(); // 999
var result = f1();//var nAdd=function(){n+=1;} n=result.n=999
var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999
nAdd();
var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999
nAdd();
nAdd();
nAdd();
result(); // 999
result2(); // 1000
result3(); // 1002