一、闭包印象
一、闭包印象
闭包是JavaScript里绕不开的话题,本文旨在让你理解闭包,阐述闭包的一些特性防止不知不觉掉坑,并在适当的条件下利用好这些特性。
关于闭包的权威定义,犀牛书上说得很透彻了(其实我看得有些晕),阮一峰老师学习Javascript闭包(Closure)和耗子哥理解Javascript的闭包讲的也深入浅出,我这里参考耗子哥的定义说明我的理解:定义在一个函数内部的函数就可以看做是闭包。来一段代码:
//代码一
var a = "gloable variable";
var F = function(){
var b = "local variable";
function N(){ //闭包
var c = "inner variable";
return b; //对父级作用域的引用
}
return N;
}
var local = F();
local(); //输出:local variable
正常情况下全局作用域是无法访问局部变量b的(作用域链原理),但是利用闭包就可以突破作用域链的限制。在代码一中,可以看成通过 var local = F()
将N变成了一个全局作用域中的函数。犀牛书上的一种解释为这是在不同的上下文环境分别定义(在函数F的作用域定义)和执行(在全局环境执行)函数所发生的微妙现象。
二、分析闭包
常说每个函数都可看做是一个闭包,当然没错,可是个人观点觉得这样的解释闭包没有实际意义,也没有说清楚闭包的特性,仅能说明闭包是一种常见现象。
个人认为,闭包的一个重要特性在于,内部函数在定义时是绑定了其所在的作用域本身的,这种绑定导致函数内部的变量值会随着作用域自身的变化而变化,而非内部函数在被定义或父级变量被返回时变量的值。举个例子:
function F(param){
function inner(){ //内部函数被定义
return param; //父级变量被返回
}
param++; //在与inner绑定的作用域修改param的值
return inner;
}
var a = F(123);
a(); //输出:124
在F中,定义和变量被返回都发生在修改变量之前,可见闭包并不会“记录”父级变量的值,而是由于这种绑定关系而忠实地反应变量实际的值。简单一点说,这里的inner在被调用时才会通过绑定关系去读取param的值,其他时候闭包并不关心param的值。
三、关于闭包的坑
既然闭包很常见,若不注意我们很可能误用了他的特性。循环中的闭包就是经常会碰到的坑。
var F = function(){
var a = [];
for(var i = 0; i < 3; i++){
a[i] =function(){ //这里定义了三个闭包
return i;
}
}
return a;
}
var arr = F();
arr[0]();
arr[1]();
arr[2](); //均输出:3
如前所述,闭包在被最后调用前都不会去读取i的值,仅仅是保留了对i的引用关系,所以最后被调用时实际读取的都是同一个i值。好吧,如何防止这种不希望的现象出现呢?
var F = function(){
var a = [];
for(var i = 0; i < 3; i++){
a[i] = function(x){ //即时函数读取i值给x
return function(){
return x;
}
}(i);
}
return a;
}
var arr = F();
arr[0](); //输出:0
arr[1](); //输出:1
arr[2](); //输出:2
通过即时函数我们在每次给数组赋值时读取i的实际值,这样就绕开了闭包的限制。
四、 闭包的实际应用
闭包最常用的地方就是setter和getter了。
假设有一个内部值,我们不能让其暴露在全局环境中以防止其被随意修改,只能通过我们规定的途径修改,当然也可以在这些途径中加入一些验证机制。举个例子:
var wenzi = (function(){
var inner = "meta-d"; //内部变量
var getValue = function(){
return inner;
}
var setValue = function(val){
if(typeof val == "string"){ //简单验证
inner = val;
}
console.info(inner);
}
return {
getValue : getValue,
setValue : setValue
}
})();
wenzi.getValue(); //输出:meta-d
wenzi.setValue("test"); //输出:meta-d
wenzi.getValue() //输出:test
除此外,闭包可用的地方还有很多,很多时候我们用了闭包但是自己并没有意识到。但万变不离其宗,了解闭包的原理才是正道。还可参考司徒大神的文章javascript的闭包
行文仓促,如有不妥之处,还请拍砖,轻拍,谢谢!