深度理解var、let、const及块级作用域

在ES5中变量作用域的基本单元是function,如果要创建一个块级作用域,则需要创建一个函数,或者使用立即调用函数表达式(IIFE)。而对于var定义的变量的作用域,作用在一个函数块中,或者存在于整个全局中(全局变量)。在ES6中出现了let和const两个变量定义方法:

let声明

与使用var声明的变量总是在函数作用域中不同,使用let声明时可以只用{…}就能创建一个作用域。

var a = 2;
{
    let a = 3;
    console.log(a);  // 3
}
console.log(a);      // 2

在let声明之前访问该变量会导致报错,这称为临时死亡区(Temporal Dead Zone, TDZ)错误。而使用var的话这个顺序是无关紧要的。

console.log(a); // undefined
console.log(b); // ReferenceError!

var a;
let b;

在for循环中使用let,不只是声明了一个变量,而是循环的每一次迭代都重新声明了一个新的变量,这点是与var不同的。

var funcs = [];
for (let i = 0;i < 5;i++) {
    funcs.push(function({
        console.log(i);
    })
}
funcs[3](); // 3
而如果把let换成var的话,打印出来的值为5

const声明

const声明用于定义常量,常量是一个设定了初始值之后就只读的变量。但是常量不是对这个值的本身进行限制,而是对赋值的那个变量限制。如果这个值时复杂值,比如对象或者数组,这个内容是可以修改的。

const a = [1,2,3];
a.push(4);
console.log(a);     // [1,2,3,4]
a = 42;             // TypeError!

块作用域函数

在ES6之前,函数调用没有块的概念,在内部定义的函数在外部也可以直接调用,而在ES6之后,块内定义的函数,其作用域就在这个块内,外部调用时会报错。函数调用支持‘提升’,即不存在TDZ错误。