闭包,英文叫做closure,借用MDN中的解释,一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。js中的闭包有以下几个特性:
1.存在函数的嵌套
2.内部函数可以引用外部的变量以及参数
3.变量以及参数 不会被垃圾回收机制回收
例子如下:
function outFn(){
var name = 'wolfBite'; // 外部函数变量
function innerFn(){ //内部函数
console.log( 'hi '+name +'!') //引用外部的变量 name
}
innerFn();
}
outFn(); // hi wolfBite!
函数outFn定义了局部变量 name 和函数 innerFn,函数innerFn中的console语句 引用name,注意函数innerFn内部没有定义局部变量name, 最后函数outFn执行了函数innerFn。调用ouFn(),打印出问候语‘hi wolfBite!’。
第二个例子如下:
function outFn(){
var name = 'wolfBite'; // 外部函数变量
function innerFn(){ //内部函数
console.log( 'hi '+name +'!') //引用外部的变量 name
}
return innerFn; //直接返回
}
var myFn = outFn(); // 接收返回值(此时outFn执行完了,但变量name并没有被回收机制回收)
myFn();// hi wolfBite!
会发现例子二和例子一的区别,函数outFn最后没有直接执行innerFn,而是将函数innerFn返回,代码最后没有直接执行函数outFn,而是将outFn的执行结果(函数innerFn)返回给变量myFn ,最后再执行myFn();
你可能会觉得执行完 ‘var myFn = outFn();’这语句之后,outFn内部定义的变量name已经被回收机制回收了,innerFn无法访问这个变量,然而代码仍按预期运行。原因是函数innerFn形成了闭包,这个闭包是由这个函数和创建该函数时的词法环境组合而成,这个环境包含了这个闭包创建时所有的局部变量。例子二中myFn 是 执行outFn时返回的innerFn实例的引用,innerFn的实例维持了一个对它的词法环境(变量 name 存在于其中)的引用,因此当myFn调用时,变量name仍可访问。