JS for循环输出异常:为什么执行后五次都打印500而非100到500?
问题原因分析
这一问题是var声明的作用域特性与闭包的变量捕获逻辑共同导致的:
- 你代码中使用
var声明的变量不存在块级作用域,只有全局/函数级作用域,因此循环中每次赋值的myindex都是同一个全局变量,不会每次循环生成独立的新变量。 - 你推入数组的箭头函数属于闭包,它捕获的是
myindex变量的引用而非循环执行时的瞬时值。
当第一轮循环全部执行完毕后,全局的myindex已经被赋值为5,此时再执行数组中存储的所有闭包函数,读取到的myindex都是已经更新到5的值,因此最终输出5次my number is:500。
常用修复方案
方案1:使用let声明块级变量
let具备块级作用域,每次循环会生成独立的myindex变量,闭包会捕获对应循环的独立变量,即可得到预期输出:
const calculatenumbers = []; for (var i = 1; i <= 5; i++) { let myindex = i; calculatenumbers.push(() => { var calculatednumber = myindex * 100; console.log('my number is:' + calculatednumber); }); } for (var j = 0 ; j < calculatenumbers.length; j++) { calculatenumbers[j](); }
你也可以直接在for循环头部用let声明i,JS会自动为每次循环生成独立的i变量,无需额外声明myindex:
const calculatenumbers = []; for (let i = 1; i <= 5; i++) { calculatenumbers.push(() => { var calculatednumber = i * 100; console.log('my number is:' + calculatednumber); }); } for (var j = 0 ; j < calculatenumbers.length; j++) { calculatenumbers[j](); }
方案2:使用立即执行函数(IIFE)锁定变量值
这是ES6推出let之前的传统解决方案,利用函数作用域锁定每次循环的瞬时值:
const calculatenumbers = []; for (var i = 1; i <= 5; i++) { (function(myindex) { calculatenumbers.push(() => { var calculatednumber = myindex * 100; console.log('my number is:' + calculatednumber); }); })(i) } for (var j = 0 ; j < calculatenumbers.length; j++) { calculatenumbers[j](); }
内容的提问来源于stack exchange,提问作者JavaScript Rookie
相关产品推荐
相关产品推荐

