You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript闭包测试出现异常?求问题排查与解决方法

聊聊你这段JavaScript闭包测试的问题

嘿,我看了你写的闭包测试代码,估计你是疑惑为什么第二段代码的输出不符合预期吧?先帮你拆解下两段代码的逻辑,再说说问题出在哪。

第一段代码为啥能正常工作?

你第一段用let声明循环变量i,这可是ES6给我们的贴心优化:let在for循环里会为每一次迭代创建一个独立的变量绑定。也就是说,每次循环push进数组的箭头函数,捕获的都是当前迭代那次的i副本,不是同一个全局变量。所以当你调用这些函数时,就会依次输出0、1、2,完全符合闭包的预期效果。

看你这段代码:

var funcList = [];
for(let i = 0; i < 3; ++i) {
    funcList.push(() => { console.log(i); });
}
console.log('testing for reference');
funcList.forEach(func => func());

第二段代码的问题出在哪?

你第二段想用立即执行函数(IIFE)来模拟ES5时代闭包捕获循环变量的写法,思路是对的,但有个小疏忽:你没把循环里的i作为实参传给IIFE!

你原来的代码是这样的:

funcList.push( ((i) => { return () => { console.log(i); } })() );

这里IIFE的参数i根本没收到实参,所以内部的i是undefined,最后调用函数时自然会输出三次undefined。

只要把循环变量i传进去就行,修正后的代码是:

funcList.push( ((i) => { return () => { console.log(i); } })(i) );

这样一来,IIFE每次都会接收当前循环的i值,内部返回的函数就会捕获这个独立的i副本,调用时也会输出0、1、2,和第一段代码效果完全一样。

补充点小知识:ES5 vs ES6的闭包写法

在ES5的时候,我们只能用var声明变量,而var没有块级作用域,循环里的所有函数都会捕获同一个i变量,最后输出都是循环结束后的3。这时候就必须用IIFE来创建独立作用域,把当前i值传进去保存。而ES6的let直接帮我们搞定了这个事,自动为每次迭代创建新的作用域绑定,写法简洁多了。

总结下:

  • 用let的循环写法是现在推荐的简洁方案,不用手动处理作用域
  • 用IIFE的传统写法一定要记得传递循环变量当实参,不然抓不到正确的值

内容的提问来源于stack exchange,提问作者Hearen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:28:28