for循环
let
//这是一个我们常见的问题
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 3
//用立即函数 解决上述闭包问题
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = (function(value){
return function() {
console.log(value);
}
}(i))
}
funcs[0](); // 0
在循环内部,立即执行函数为接受的每一个变量 i 都创建一个副本并保存为变量value
//用ES6中let解决上述问题 (栗 1)
var funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 0
在这里let解决闭包的原因是什么呢?
我们了解的 let 不存在变量提升,不能重复声明,不能绑定全局作用域
,可是为什么在这里就能正确打印出 i 值呢?
有人猜想说 for 循环中,设置循环变量的那部分是一个单独的作用域:
我们暂且将上面的问题放一放~~
先来看另一个栗子,看看猜想是否正确:
for (let i = 0; i < 3; i++) {
let i = 'ES6';
console.log(i);
}
// ES6
// ES6
// ES6
我们再试一试用var声明的变量
for (var i = 0; i < 3; i++) {
var i = 'ES6';
console.log(i);
}
// ES6
为什么结果就不一样了呢,如果有单独的作用域,结果应该是相同的呀……
*注意: let 声明在循环内部的行为是标准中专门定义的
,不一定就与 let 的不提升特性有关。
在 for 循环中使用 let 和 var,底层会使用不同的处理方式。
其实呢上面的代码是这样解释的:就是在 for (let i = 0; i < 3; i++) 中,即圆括号之内建立一个隐藏的作用域。
每次迭代循环时都创建一个新变量,并以之前迭代中同名变量的值将其初始化
通俗的来说~~ 每次循环的时候let都会 创建一个新的变量 i 并将其初始化为i的当前值。
栗1 的代码就相当于:
// 伪代码
(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 i=6;
for(let i=0;i<3;i++)
{
let i;
console.log(i); //undefied undefied undefied
//可以将{}内部的看成子作用域 ()内部的看成父作用域
}
const
那我们将上面的 let 改为const呢?
var funcs = [];
for (const i = 0; i < 10; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); //报错 因为const中的绑定不可被修改
for in
我们上面说的都是普通的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]()
用var声明打印结果为’c’
用let声明,结果为’a’
const呢?它没有报错,输出结果还是’a’这是因为在 for in 循环中,每次迭代不会修改已有的绑定,而是会 创建一个新的绑定。
const的特点是在块级作用域内不能重复声明,且不能给它重新赋值(重点是块级作用域)。for in的每一次循环都是一个新块级作用域,所以可以使用for(const a in b)的形式去遍历对象的。