先说一个众所周知的作用域问题,看一下代码:
var a = []; for (var i = 0; i < 5; i++) { a.push(function () { console.log(i) }); } a[0](); a[1]();
以上期望输出0, 1,实际输出则是 5,5。因为i的作用域是window(global)全局。
ES6有个解决办法,把var关键字改为let关键字,即可解决作用域问题。原理可以通过babel转换一下源码探知:
var a = []; var _loop = function _loop(i) { a.push(function () { console.log(i); }); }; // 源码是let声明,此处经过了babel转换 for (var i = 0; i < 5; i++) { _loop(i); }
通过循环体封装为_loop函数,把i转为一个函数内部变量,不再受循环外变量影响。
而此时也该点题了,本文题目说的是另外一个隐藏的坑。见以下代码:
const a = []; for (let i = 0; i < 5; ) { a.push(function () { console.log(i) }); i++; // 条件改变放到循环体内 } a[0](); a[1]();
不同之处也已标明:i++的条件改变位置换到了循环体内执行,这时预期结果也不一样了。
执行预期应该是输出0, 1,实际却输出的是 1, 2。
这是为什么呢?同样通过babel转换源码后探知:
var a = []; var _loop = function _loop(_i) { a.push(function () { console.log(_i); }); _i++; // 循环体内的条件改变影响到循环体函数内的局部变量 i = _i; }; for (var i = 0; i < 5;) { _loop(i); } a[0](); a[1]();
最近也是在写一个比较复杂的业务逻辑时,发现这种写法的问题,好在花费了一些时间总算是搞清楚了。
如果循环体是即时执行是不会有问题的,如果是延迟执行的则会暴露该问题。