Пожалуйста, обратитесь к этому Как работают закрытия JavaScript?
Это может помочь вам понять замыкания.
Всякий раз, когда вы видите ключевое слово функции в другой функции, внутренняя функция имеет доступ к переменным во внешней функции.
function foo(x) {
var tmp = 3;
function bar(y) {
alert(x + y + (++tmp));
}
bar(10);
}
foo(2)
Это всегда выдаст 16, потому что bar
может получить доступ к x
, который был определен как аргумент для foo
, и также может получить доступ к tmp
из foo
.
То, что является закрытием. Функция не должна возвращать , чтобы вызываться замыканием. Простой доступ к переменным вне вашей непосредственной лексической области создает замыкание .
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + (++tmp));
}
}
var bar = foo(2); // bar is now a closure.
bar(10);
Вышеприведенная функция также выдаст предупреждение 16, поскольку bar
может по-прежнему ссылаться на x
и tmp
, даже если она больше не находится непосредственно внутри области действия.
Однако, поскольку tmp
все еще находится внутри закрытия bar
, оно также увеличивается. Он будет увеличиваться каждый раз, когда вы звоните bar
.
Простейший пример закрытия - это:
var a = 10;
function test() {
console.log(a); // will output 10
console.log(b); // will output 6
}
var b = 6;
test();
Когда вызывается функция Javascript, создается новый контекст выполнения. Вместе с аргументами функции и родительским объектом этот контекст выполнения также получает все переменные, объявленные вне его (в вышеприведенном примере оба 'a' и 'b').
Можно создать более одной функции замыкания, либо возвращая их список, либо задавая им глобальные переменные. Все они будут относиться к одинаковым x
и тем же tmp
, они не делают свои собственные копии.
[you]: Увлекательно, расскажи мне больше!
Здесь число x
является буквальным числом. Как и в случае с другими литералами в JavaScript, при вызове foo
число x
равно , скопировано в foo
в качестве аргумента x
.
С другой стороны, JavaScript всегда использует ссылки при работе с объектами. Если, скажем, вы вызвали foo
с объектом, возвращаемое им закрытие будет ссылаться на этот оригинальный объект!
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + tmp);
x.memb = x.memb ? x.memb + 1 : 1;
alert(x.memb);
}
}
var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);
Как и ожидалось, каждый вызов bar(10)
будет увеличиваться x.memb
. Чего нельзя ожидать, так это того, что x
просто ссылается на тот же объект, что и переменная age
! После пары звонков на bar
, age.memb
будет 2! Эта ссылка является основой для утечек памяти с объектами HTML.