前言
for (var i = 0; i < 6;i++) {
setTimeout(function () {
console.log(i)
}, 1000)
}
我们都知道以上代码在ES5中会输出6个6。如果我们想要的结果是输出0 1 2 3 4 5,在ES6中可以将以上的var替换成let来得要想要的结果。那以下我们通过babel来将四段ES6代码编译成ES5来推测ES6中let在for中表现的原理。
代码片段一(将var替换成let)
编译前
for (let i = 0; i < 6; i++) {
setTimeout(function () {
console.log(i)
}, 1000)
}
输出 0 1 2 3 4 5
编译后
"use strict";
var _loop = function _loop(i) {
setTimeout(function () {
console.log(i);
}, 1000);
};
for (var i = 0; i < 6; i++) {
_loop(i);
}
结论:for循环内部(花括号内)是一个独立的作用域,babel编译后用函数作用域来模拟,通过类似传入函数参数的方式将i变量传入循环内部作用域中,因此setTimeout中使用的是每次循环时候的i的值。
代码片段二(在外部访问for循环中初始化的变量)
编译前
for (let i = 0; i < 6; i++) {
setTimeout(function () {
console.log(i)
}, 1000)
}
console.log(i)
输出 0 1 2 3 4 5
输出 ReferenceError
编译后
"use strict";
var _loop = function _loop(_i) {
setTimeout(function () {
console.log(_i);
}, 1000);
};
for (var _i = 0; _i < 6; _i++) {
_loop(_i);
}
console.log(i);
结论:在for循环初始化中的用let定义的i不属于父级作用域,属于for循环的作用域,由于ES5中没有块级作用域,所以编译后只能用_i来区分。
代码片段三(将i定义在外部)
编译前
let i;
for (i = 0; i < 6; i++) {
setTimeout(function () {
console.log(i)
}, 1000)
}
输出 6 6 6 6 6 6
编译后
var i = void 0;
for (i = 0; i < 6; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
结论:当i定义在外部的时候,与ES5中的表现基本相同。
代码片段四(在循环内部修改i的值)
编译前
for (let i = 0; i < 6; i++) {
i++
setTimeout(function () {
console.log(i)
}, 1000)
}
输出 1 3 5
编译后
"use strict";
var _loop = function _loop(_i) {
_i++;
setTimeout(function () {
console.log(_i);
}, 1000);
i = _i;
};
for (var i = 0; i < 6; i++) {
_loop(i);
}
结论:若在for循环内部对传入的变量进行了修改,在每个内部循环结束时会将修改后的值重新赋值给这个变量。
总结
/* outer */
for (let i = 0 /* for */ ; i < n; i++) {
/* inner */
}
不考虑for循环内部生成的其他作用域,通过let在for循环中初始化变量时会产生三类作用域,按从外而内的关系表示为 outer
for
inner
,在上述代码中会产生 n
个相互独立的 inner
作用域。在 for
中的通过let初始化的变量(i
),会以类似传递函数参数的形式被 inner
中代码使用,在一次 inner
中代码执行完成后,若传入的变量被改变,会将改变后的值重新赋值给 for
中的变量(i
)。
如有不同意见,欢迎讨论。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!