闭包

闭包是指有权访问另一个函数作用域中的变量的函数。这是JavaScript中对闭包的解释。

function fn1 () {

var age = 20;

return function () {
return age;
}
}


var fn2 = fn1();
var age = fn2();
console.log(age); //20

也许你会觉得,fn1中返回的匿名函数是在全局环境中被调用的,然而,它却能访问fn1函数中的局部变量age。
其实,这里面与作用域链机制紧密相关,因为,被返回并保存在fn2变量中的匿名函数的作用链列表中,包含了fn1函数的活动对象的引用,包括全局的变量对象。
一般来讲,函数执行完毕后,其活动对象就被销毁了,但这里的情况不同,这是因为fn1函数内部返回了一个匿名函数,
并被保存在了一个全局变量上,而这个匿名函数的作用域链中保存着对fn1的活动对象的引用
所以,当fn1函数执行完毕了之后,它的活动对象并没有因此被销毁,就因为还有其他地方保存着对这个活动对象的引用,
那就是从fn1函数被返回,然后保存在fn2中的那个函数。

fn2 = null;

这里我们解除fn2变量对函数的引用,由此,那个从fn1函数中返回的匿名函数在垃圾自动回收机制中被清除,
由此,除了全局变量对象,不论是fn1或者是匿名函数内部的变量对象都会失去引用,被销毁掉。内存得到释放。

一道较常出现的面试题

function fn () {
var arr  = [];

for(var i = 0; i < 10; i++) {

arr.push(function () {
console.log(i)
})
}

return arr
}

var arr = fn();

arr[0]()//10
arr[1]()//10
arr[2]()//10
...
arr[9]()//10

也许你会认为数组中的每个函数打印出的值是1,2,3,4…这样的顺序,但其结果其实是10
可以想象,当循环结束后,变量i已经被累加到了10,循环结束后,数组被返回。
当我们调用数组中的函数的时候,这个i究竟从哪里被查询到的?很显然,在匿名函数的活动对象中并不存在i这个变量,
那么,沿着作用域链,就会找到fn函数的活动对象,这个活动对象当中,保存着i变量,其值为10,这样,
这个值就被返回打印出来了。

为了让每个函数返回的值都如预期的那样,如1,2,3,4…,那么,我们可以这样做。

function fn () {
var arr  = [];

for(var i = 0; i < 10; i++) {

function storage_i (i) {
arr.push(function () {
console.log(i)
})
}

storage_i(i)
}

return arr
}

var arr = fn();

arr[0]();//0
arr[1]();//1
arr[2]();//2
arr[3]();//3
arr[4]();//4
...
arr[9]();//5

做法很简单,就是把匿名函数套进一个函数内,这个函数会接收每次循环时传递进来的变量i,这样一来,
每次循环变化的i都会存储在storage_i函数内,在匿名函数的作用域链中的第二位为storage_i的活动对象,
当匿名函数在自己的活动对象中找不到变量i的时候,自然会到storage_i的活动对象中找,而storage_i的活动对象中保存着
每次循环变化的i,注意这里每个函数访问的不再是同一个活动对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值