JS闭包
先贴一段代码,如下:
function Test(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = function () {
console.log('打印:' + i )
}
}
return arr;
}
var myArr = Test();
//在我的想象中,函数执行结果应该是1 2 3 4 .... 9,
//但是事实上全是10, 为什么?
for(var j = 0; j < 10; j++){
myArr[j]();
}
1,为什么结果是输出10个10而不是0~9?
分析上述代码,当Test()函数执行的前一刻,会生成函数的执行期上下文AO(Active Object)
此时Test的AO里面有var arr,var i,在函数执行的过程中i循环++ = 10,并循环时向arr的第i位
添加了一个函数,循环结束,将arr抛出Test函数,此时Test执行完毕,销毁自己的执行期上下文
但是在Test函数执行快要结束的前一刻,arr被return出来,此时arr里面保存了10个function,并且
这些函数是在Test里面出生的,拥有Test函数的执行期上下文AO,所以Test函数执行完成时销毁他自己的AO却别arr保存了出来,此时的作用域链是无法释放的,以至于形成了闭包,
简而言之,闭包就是在函数内部定义函数,并把内部函数保存到了外面来执行,此时内部函数使用的执行环境还是父函数的环境,虽然父函数被销毁了,但是它的AO无法销毁,被内部函数保存到了外部。
以上代码在执行完Test的时候 i的值 = 10;所以Test的AO里面i = 10;又因为Test的AO被arr保存了出来,所以在执行arr的时候console.log(‘打印’ + i) 的时候arr函数也会生成一个自己的AO 但是它的AO里面没有i 所以它会向它作用域链的上一环寻找,而上一环正是Test的AO 所以打印 i = 10;
2,如何解决此类问题?
通过代码可以看出通过for循环生成10个function 形成了一个1对10的闭包,解决这个问题,可以把问题转化成10对10的闭包问题,利用立即执行函数可解决
function Test(){
var arr = [];
for(var i = 0; i < 10; i++){
/***
** 因为立即执行函数是立即执行的 把i当着实参传入立即执行函数
** 此时立即执行函数形成了自己的AO 所以此时arr[j]的执行环境是立即执行函数的AO
***/
(function (j){
arr[j] = function () {
console.log('打印:' + j )
}
}(i))
}
return arr;
}
var myArr = Test();
//在我的想象中,函数执行结果应该是1 2 3 4 .... 9,
//但是事实上全是10, 为什么?
for(var j = 0; j < 10; j++){
myArr[j]();
}
3,闭包的一些作用及危害
作用:
- 实现变量的私有化
- 在内存中维持一个变量,可以做缓存
危害:
- 由于闭包造成作用域链的不释放,会占用多余的内存,造成内存泄漏
- 其次由于闭包涉及跨域访问,所以会导致性能损失