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
相关产品推荐
相关产品推荐

