缘起
下面是js考察闭包的经典问题:
var a = [];
for(var i=0;i<10;i++){
a[i] = function(){
console.log(i);
}
}
console.log(a[6]()) // 10
要使输出为6,一般这样构建闭包:
var a = [];
for(var i=0;i<10;i++){
(function(i){
a[i] = function(){
console.log(i);
}
})(i);
}
console.log(a[6]()) // 6
ES6引入块级作用域之后,可以这样实现:
var a = [];
for(let i=0;i<10;i++){
a[i] = function(){
console.log(i);
}
}
console.log(a[6]()) // 6
误解
由于自己有一点C语言基础,很容易将上述ES6实现理解为:
var a = [];
let i;
for(i=0;i<10;i++){
a[i] = function(){
console.log(i);
}
}
console.log(a[6]()) // 10
在C中,int定义在for内括号还是for之外是一样的,为什么这里输出了10?
- 块级作用域是以{}标识的,for循环应该生成十个{}子块作用域
- 每个子块{}中关联的是相应的i,即每次循环的i值
- let放在for语句内和for语句外部应该都在十个{}子块的外部,都初始化一次,为什么会产生不一致?
原因
根本上在于,let放到for的括号内js在底层机制处理上另有标准相关标准ES6写法分解为伪代码应该如下:
(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定义的变量值
- 这似乎与“经验不符”,产生这样的误解根本还是JS语言的丰富性和语言最初设计的“灵活”,这造成了后面标准升级polyfill时不可避免地留下此类的坑。
- 学习JS务必要清楚落实到标准上,一定要求甚解,理解什么是语法糖什么是“公理性”语法
评论 0
还没有评论,来抢个沙发吧。