JavaScript学习总结——闭包的一个问题

本文深入探讨JavaScript中闭包的一个常见误区,即在循环中使用闭包导致的所有函数引用同一变量的问题。通过具体示例,解释为何会出现预期外的结果,并提供解决方案,帮助读者理解闭包的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

理解闭包以后,我们来看看闭包会带来什么问题

function test() {
	
	var arr = [];
	for(var i=0; i<10; i++) {
		arr[i] = function () {
			document.write(i + ' ');
		}
	}
	return arr;
}
var myArr = test();
for (var j=0; j<10; j++) {
	myArr[j]();
}

在函数test( )中定义一个空数组,再通过for循环往数组中添加十个输出函数用于输出当前的索引,将数组返回给变量myArr,通过for循环执行,希望输出结果为0 1 2 3 4 5 6 7 8 9,实际输出结果却是十个10,为什么呢?

为什么是10?

在test( )执行过程中,for循环判断完i<9为true后,会继续进行i++操作。此时,i为10。再次判断i<10未false,结束循环。因为输出函数在test( )执行完毕后才被执行,这时回头找i变量,已经是10了。

为什么是十个都是10?

可能会有人有疑问,在for循环执行过程中,i的值在自增,那为什么输出结果中的i跟数组索引i不是同一个值呢?因为for循环的执行会一直改变arr[ ]的索引值,而把函数引用赋给数组arr[ ]的过程中,函数并未被执行,函数体的内容根本不会被改变。(预编译可知,函数只有在执行的时候(前一刻)才会创建自己的执行期上下文,系统都不知道未执行的函数里写的是啥)等到函数被执行时,十个输出共用的执行期上下文中的i已经是10。
简单来讲上述代码应该这样来看

function test() {
	
	var arr = [];
	for(var i=0; i<10; i++) {
		arr[i] = function () {
			document.write(i + ' ');//忽略函数体内容,因为未被执行
		}
	}
	return arr;
}
var myArr = test();
for (var j=0; j<10; j++) {
	myArr[j]();//在执行时再来查找函数体document.write(i + ' ');此时i已经为10
}
解决方法
function test() {
	
	var arr = [];
	for(var i=0; i<10; i++) {
		(function(j) {
			arr[j] = function () {
				document.write(j + ' ');
			}
		}(i))
	}
	return arr;
}
var myArr = test();
for (var j=0; j<10; j++) {
	myArr[j]();
}

将内层函数用立即执行函数包裹,将i作为参数传给立即执行函数。每次执行循环时,立即执行函数执行,创建AO{}对象保存参数,并将AO{}对象放在作用域链顶端(同时内层函数被创建且作用域链与立即执行函数相同),然后立即执行函数销毁,内层函数的引用被保存在数组中,形成闭包。执行十次for循环会创建十个立即执行函数。虽然最内层函数还是未被执行,但是在内层函数被执行时,内层函数的作用域链中包含着包裹自己的立即执行函数的AO{}对象。此时再通过各自的作用域链中,立即执行函数的AO{}对象查找到参数的值,输出得到想要的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值