二、闭包
2019-03-30 本文已影响0人
萘小蒽
闭包是指有权访问另一个函数作用域的变量的函数。
function createComparisonFunction(propertyName){
return function(object1,object2){
var value1 = object1[propertyName]; // 注意点
var value2 = object2[propertyName]; // 注意点
if(value1 < value2){
return - 1;
}else if(value1 > value2){
return 1;
}else{
return 0;
}
}
}
- 上面匿名函数中的两行代码(
注意点
),访问了外部函数中的变量propertyName
,即使这个内部函数被返回了,且在其他地方被调用了,但仍然可以访问变量propertyName
。- 之所以能访问,是因为内部函数的作用域链中包含了
createComparisonFunction()
的作用域,往下看。
var compare = createComparisonFunction("name");
var result = compare({name:"yujia"},{name:"yujiajia"});
compare = null; //解除对匿名函数的引用,以便释放内存
- 在
createComparisonFunction()
被调用之后,它的作用域链初始化为包含createComparisonFunction()
函数的活动对象和全局变量对象。这样内部的匿名函数可以访问createComparisonFunction()
定义的全部变量。createComparisonFunction()
执行完毕(返回匿名函数
)后,它的活动对象不会被销毁(活动对象依然留在内存中
),因为匿名函数的作用域链仍然在引用createComparisonFunction()
的活动对象
由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存,请谨慎使用。
作用域链的机制引出了一个值得注意的副作用,就是闭包只能取得包含函数中任何变量的最后一个值。
function createFunction(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(){
return i
}
}
return result
}
createFunction()[1]() //10
createFunction()[2]() //10
createFunction()[3]() //10
上面的函数组成的数组看上去每个
result
数组中的函数都会返回其对应的下标记,但是都返回了10。
原因是result
中的函数(闭包
)保存的是createFunction()
函数的活动对象,所以他们引用的都是同一个变量i
,当createFunction()
返回数组后,变量i
的值是10.
这样能强制让闭包的行为符合预期,或者将var
变成let
:
function createFunction(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(){
return function(name){
return name
}
}(i)
}
return result
}
this
在闭包中this
对象也可能会导致一些问题
var name = "the window";
var object = {
name:"My Object",
getNameFunc:function(){
return function(){
console.log(this.name)
}
}
}
object.getNameFunc()() // "the window"
- 函数在被调用的时候,会自动取得两个特殊变量
this
和arguments
。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能访问到外部函数中的这两个变量。- 要知道,上面也只是在
getNameFunc()
返回了一个匿名函数,而调用这个匿名函数的作用域环境是window
。
不过,我们可以把外部作作用域中的this
对象保存在一个闭包能访问到的变量里:
var name = "the window";
var object = {
name:"My Object",
getNameFunc:function(){
var that = this;
return function(){
console.log(that.name)
}
}
}
object.getNameFunc()() // "My Object"