js中的闭包
在正文前面普及一下:
js定义的变量分为全局变量和局部变量
js可以在函数内部调取全局变量
js函数外部不能取到函数内部定义的变量
js平级函数不能相互读取函数内部定义的变量
js闭包特殊之处就是函数2可以得到函数1的私有变量
--------------------------------------------------------------------------------------我是分割线------------------------------------------------------------------------------------------------------------------
什么是闭包?
百度给出的答案是:指可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。
说实在的这句话反正我是没看懂,查阅书籍,发现闭包是指有权访问另一个函数作用域的变量的函数,常见创建闭包的方式就是在一个函数内部在创建另外的函数,
例如:
function funct1(){ var num1="10"; function funct2(){ alert(num1); } return funct2; } var obj = funct1(); obj();
当然上面的例子funct1也可以直接返回一个匿名函数,
通过概念和案例,我对闭包的理解就是:能够获取函数内部私有变量的函数,
而在js的语法中,只有函数内部的子函数才能获取私有变量,所以闭包要写在函数内部,
闭包有两大作用:
1、访问函数内部的私有变量,
2、函数内部的私有变量不会被回收
1不用解释,2原因是将函数funct1返回的funct2函数赋给全局变量obj,此时funct2也是全局函数,而funct2函数有调用函数funct1的私有变量,级funct2函数依赖于funct1函数,因此funct1函数也会保留在内存里,不会被回收。
注意因为闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存,过度使用闭包会导致内存占用过多;闭包会在父函数外部改变父函数的私有变量,所以若将父函数当对象使用,把闭包当共有方法,把内部变量当成私有属性,这时切记请勿轻易改变父函数内部变量的值
说起闭包就需要引入作用域链,作用域链这种机制引入一个很大的副作用,即闭包只能获取包含函数中任何变量的最后一个值,如下面闭包:
function funct1(){ var result = new Array(); for(var i=0;i<10;i++){ result[i]= function (){ return i; } } return result; }
var functs=funct1();
for(var i=0;i<functs.length;i++){
console.log(functs[i]())
}
这个函数我们期望的是输出从0到9的数,可是事实并不是这样,它输出了10个10,也就是闭包输出的每次都是funct1函数变量i的最后一个值(10),这当然不是我们所期望的,这时需要引入一个匿名函数强制让闭包的行为符合预期:
function funct1(){ var result = new Array(); for(var i=0;i<10;i++){ result [i] = function (num){ return function(){ return num; } }(i); } }
var functs=funct1();
for(var i=0;i<functs.length;i++){
console.log(functs[i]())
}
此时运行此闭包就能完美输出从0到9的数,现在我们分析一下,这测版本中我们并没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行匿名函数所得的结果赋给数组,这里的匿名函数有一个参数num,也就是最重要返回的值,在调用每个匿名函数时我们传入了变量i,由于函数参数是按值传递的,所以就会将变量i的当前值赋给num,而这个匿名函数内部有创建并返回了了一个访问num的闭包,这样result数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的数值了
当然this在闭包中也是比较好玩的,
var num=10; var obj= { num=20; alertNum;function(){ return function(){ return this.num; } } } alert(obj.alertNum()()); //输出10
内部函数在搜索this和arguments两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量,不过把外部作用域中的this对象保存在一个闭包能够访问的变量里,就可以让闭包访问该对象了,如下面代码
var num=10; var obj= { num=20; alertNum;function(){ var that = this; return function(){ return that.num; } } } alert(obj.alertNum()()); //输出20