请参考这个How do JavaScript closures work?
这可以帮助你理解闭包。
每当您在另一个函数中看到 function 关键字时,内部函数就可以访问外部函数中的变量。
function foo(x) {
var tmp = 3;
function bar(y) {
alert(x + y + (++tmp));
}
bar(10);
}
foo(2)
这将始终警告 16,因为bar 可以访问被定义为foo 的参数的x,它还可以从foo 访问tmp。
是一个闭包。一个函数不必为了被称为闭包而返回。 简单地访问直接词法范围之外的变量会创建一个闭包。
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,它们不会自己制作副本。
[你]:太迷人了,告诉我更多!
这里的数字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 对象内存泄漏的基础。