js 闭包经典问题超详细解析

闭包经典问题

闭包经典问题如下:

function test() {
	var arr = [];
	for(var i = 0; i < 10; i++){
		arr[i] = function () {
			console.log(i + " ");
		}
	}
	return arr;
}

var myArr = test();
for(var j = 0; j < 10; j++) {
	myArr[j]();
}

本意是想打印1到10,却打印了10个10,为什么呢?详细解释过程如下:

  • test函数预编译:
test-AO: {
	arr: undefined,
    i: undefined
}
  • test函数执行:赋值后,进入循环语句,也是赋值,因此将10个内容相同的函数体赋值给arr数组,在循环外层加一个打印语句可以看出:arr的值为

但此时匿名函数的作用域链为:

[[scope]]---->scopechain[0]---->test-AO;

                 ---->scopechain[1]---->GO;

最后,将arr返回。

  • 最后,到全局环境中循环执行arr中的各个函数,此时,匿名函数的作用域链为:

[[scope]]  ---->scopechain[0]---->AO;

                 ---->scopechain[1]---->test-AO;

                 ---->scopechain[2]---->GO;

首先在自身AO寻找i,未找到,则到下一层,test-AO寻找i,但此时由于10次循环都已经执行完,test-AO中i为10,因此打印了10个10。

解决办法

上面打印10个10的原因是i并没有个性化地保存在函数的作用域链中,因此,我们的目的就是将其保存在作用域链中。

采用立即执行函数来解决这个问题。先简单介绍一下立即执行函数:

  • 函数会立即执行,执行完后就被销毁;
  • 一般针对初始化功能的函数,比如计算某些值,不需要再第二次使用的函数。
  • 两种写法:
    (function (b) {} (a)); //外层括号将其转化为表达式,因此可以被执行
    (function (b) {})(a);
    // 注意:()为执行符号,只有表达式才能被执行符号执行

    因此上面的例子可以改写为:

function test() {
	var arr = [];
    for(var i = 0; i < 10; i++) {
        (function (j) {
		    arr[j] = function () {
			    console.log(j + " ");
		    }
         } (i));
    }
	return arr;
}

var myArr = test();
for(var j = 0; j < 10; j++) {
	myArr[j]();
}

 可以看出,在原来的基础上,在arr赋值语句外层包了一个立即执行函数,这个函数的目的就是将i的值保留在function () {console.log(j + " ");}的作用域链中,我们从头来解析一下这个函数:

  • 执行test函数:进入循环后,执行立即执行函数

当i为0时,传给j,此时a[0]仍被赋值为函数体function () {console.log(j + " ");},但这个时候,该函数的作用域链为:

[[scope]]  ---->scopechain[0]---->立即执行函数的AO;

                 ---->scopechain[1]---->test-AO;

                 ---->scopechain[2]---->GO;

此时,立即执行函数的AO为:

AO:{
    j: 0
}

当i为1时,传给j,此时a[1]仍被赋值为函数体function () {console.log(j + " ");},同样,该函数的作用域链为:

[[scope]]  ---->scopechain[0]---->立即执行函数的AO;

                 ---->scopechain[1]---->test-AO;

                 ---->scopechain[2]---->GO;

此时,立即执行函数的AO为:

AO:{
    j: 1
}

注:即使执行同一个函数,每次执行均会产生不同的AO。

依此类推,可以看出,当执行数组里面的每个函数时,会到其作用域链自顶向下查找,从而可以打印出0-9.

发布了53 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/bingqise5193/article/details/99772363