原文地址:How do javascript closures work?
任何时候当你看到函数关键字中有另外一个函数时,里面的函数都可以方位外部的函数。
function foo(x) {
var tmp = 3;
function bar(y) {
alert(x + y + (++tmp)); // will alert 16
}
bar(10);
}
foo(2);
结果总是16,因为bar
可以方位x
,x在foo
中被定义为一个参数。
这就是闭包。函数不一定返回,从而叫做闭包。
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + (++tmp)); // will also alert 16
}
}
var bar = foo(2); // bar is now a closure.
bar(10);
上面的函数也会返回16,因为bar
仍然可以引用x
和tmp
,尽管不直接存在于作用域中。
然而,因为tmp
仍然存在与bar
的闭包中。它也会增加。每次你调用bar
时,他都会增加。下面是一个关于闭包的简单例子:
var a = 10;
var b = 6;
function test() {
console.log(a); // will output 10
console.log(b); // will output 6
}
test();
当Javascript函数被调用时,一个新的执行上下文被创建。连同函数参数和父对象, 这个执行上下文也接受所有的外部声明(在上面的例子中,‘a’和‘b’都是)
有可能创建不止一个闭包函数,或者通过设置它们的全局变量返回它们的列表。这些都有一个相同的x
和相同的tmp
,他们没有复制自己。
这个数字x
是数字字面量。作为在Javascript的其他字面量,当foo
被调用时,这个数字x
被作为参数复制到了foo
。
另一方面,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 = 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对象的内存泄露的基础。