ES6-循环中的块级作用域

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)的形式去遍历对象的。

你可能感兴趣的:(ES6)