babel.png注意: 所有代码都是用ES6在线测试,分享给大家。
经典面试题:
var funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = (function(i){
return function() {
console.log(i);
}
}(i))
}
funcs[0](); // 0
解决方案 let:
很多人都知道可以用let来解决输出1、2、3,为什么可以?下面我们讲解这里面的原理。
我们知道let 声明的变量不存在变量提升、重复声明、不能绑定全局作用域等等特性,可是为什么在这里就能正确打印出 i 值呢?
如果是不重复声明,在循环第二次的时候,又用 let 声明了 i,应该报错呀,就算因为某种原因,重复声明不报错,一遍一遍迭代,i 的值最终还是应该是 3 呀,有人说 for 循环的设置循环变量的那部分是一个单独的作用域,就比如:
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
如果我们把 let 改成 var 呢?
for (var i = 0; i < 3; i++) {
var i = 'abc';
console.log(i);
}
// abc
为什么结果就不一样了呢,如果有单独的作用域,结果应该是相同的,但是不相同。
我们查看 ECMAScript 规范第 13.7.4.7 节:
es.png我们会发现,在 for 循环中使用 let 和 var,底层会使用不同的处理方式。
那么当使用 let 的时候底层到底是怎么做的呢?
简单的来说,就是在 for (let i = 0; i < 3; i++) 中,即圆括号之内建立一个隐藏的作用域,这就可以解释为什么:
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
然后每次迭代循环时都创建一个新变量,并以之前迭代中同名变量的值将其初始化。这样对于下面这样一段代码:
var funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 0
就相当于:
// 伪代码
(let i = 0) {
funcs[0] = function() {
console.log(i)
};
}
(let i = 1) {
funcs[1] = function() {
console.log(i)
};
}
(let i = 2) {
funcs[2] = function() {
console.log(i)
};
};
如果将let 改成const ,会出现什么情况呢?答案一想就知道:每次迭代的过程中去修改const 定义的值是不允许的。
说完了普通的 for 循环,我们还有 for in 循环呢~
var funcs = [], object = {a: 1, b: 1, c: 1};
for (var key in object) {
funcs.push(function(){
console.log(key)
});
}
funcs[0]()
结果是 'c';
那如果把 var 改成 let 或者 const 呢?
使用 let,结果自然会是 'a',const 呢? 报错还是 'a'?
结果是正确打印 'a',这是因为在 for in 循环中,每次迭代不会修改已有的绑定,而是会创建一个新的绑定。
编译let:
我们再写个直观的例子:
let value = 1;
{
let value = 2;
}
value = 3;
var value = 1;
{
var _value = 2;
}
value = 3;
本质是一样的,就是改变量名,使内外层的变量名称不一样。
那像 const 的修改值时报错,以及重复声明报错怎么实现的呢?
其实就是在编译的时候直接给你报错……
那循环中的 let 声明呢?
var funcs = [];
for (let i = 0; i < 10; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 0
Babel 巧妙的编译成了:
var funcs = [];
var _loop = function _loop(i) {
funcs[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
funcs[0](); // 0
这也是为什么可以用必包解决这个问题?
var funcs = [];
for (var i = 0; i < 10; i++) {
(function (i) {
funcs[i] = function () {
console.log(i);
};
})(i);
}
funcs[0](); // 0
网友评论