闭包:当一个函数在其被声明的作用域环境外被执行时,它可以记住和使用它原本作用域中的变量。
function foo(){
var a = 2;
function bar(){
console.log(a);
}
return bar;
}
var baz = foo();
baz(); //2
bar函数可以使用foo函数内的变量。而当最后baz函数执行时,其实是bar函数执行,bar函数很显然地在其被声明的作用域外被调用,但是最后还是输出了2.
一般可能会觉得在foo函数执行完毕后,其内部作用域会消失(根据js垃圾回收机制)。但是由于闭包的存在,foo的内部作用域还一直存在在那里,bar函数仍然对此作用域有引用,而这个引用就是闭包。
因此当baz执行时(其实是bar执行),它依旧能使用它被声明时的作用域环境,因此就能使用变量a。
类似的,还有很多种将函数作为参数来传递的情况,这时函数就有可能在其他位置被执行。如:
function foo(){
var a = 2;
function baz(){
console.log(a);
}
bar(baz);
}
function bar(fn){
fn(); //实际调用的是foo的内部函数,为闭包
}
var fn;
function foo(){
var a = 2;
function baz(){
console.log(a);
}
fn = baz; //把baz传递给了一个全局变量
}
function bar(){
fn(); //实际调用的是foo的内部函数,为闭包
}
foo();
bar(); //2
不管通过什么方式将内部函数传递到外部,它都会维持对其最初被声明时的作用域环境的引用,而且不管在何处调用此函数,闭包都会被执行。
看一个例子:
function wait(message){
setTimeout(function timer(){
console.log(message);
},1000);
}
wait("hello closure");
内部函数timer做为setTimeout的参数,内部函数的词法作用域包含外部wait函数的作用域,因此timer会一直保持一个对变量message的引用。
执行wait函数,当1000毫秒过去时,异步的内部函数timer利用闭包可以继续使用变量message。