什么是闭包
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。我们先看一段代码
function foo() {
var a = 2;
function bar() {
console.log( a ); // 2
}
bar();
}
foo();
上面这个是闭包吗?很遗憾,从定义的角度来说它并不是。
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo();
baz(); // 2 ———— 朋友,这就是闭包的效果。
我们用全局变量baz
接收了 foo返回的函数 bar
,因此我们阔以在其他任何作用域中使用 baz
去获取 foo内部的元素。这种就是闭包。
var fn;
function foo() {
var a = 2;
function baz() {
console.log( a );
}
fn = baz; // 将baz分配给全局变量
}
function bar() {
fn(); // 妈妈快看呀,这就是闭包!
}
foo();
bar(); // 2
无论通过何种手段将内部函数传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。
如果你很熟悉jQuery(或者其他能说明这个问题的JavaScript框架),可以思考下面的代码:
function setupBot(name, selector) {
$( selector ).click( function activator() {
console.log( "Activating:" + name );
} );
}
setupBot( "Closure Bot 1", "#bot_1" );
setupBot( "Closure Bot 2", "#bot_2" );
本质上无论何时何地,如果将函数(访问它们各自的词法作用域)当作第一级的值类型并到处传递,你就会看到闭包在这些函数中的应用。在定时器、事件监听器、Ajax请求、跨窗口通 信、Web Workers或者任何其他的异步(或者同步)任务中,只要使用了回调函数,实际上就是在使用闭包!
闭包的特点
- 让外部访问函数内部变量成为可能;
- 局部变量会常驻在内存中;
- 可以避免使用全局变量,防止全局变量污染;
- 会造成内存泄漏(有一块内存空间被长期占用,而不被释放)