块级绑定

因为ES6之前存在变量提升问题,容易造成问题,ES6引入了块级作用域。

块级声明

块级作用域在函数或者块({})中创建。

let声明,不提升,不可重复声明。

例子1(报错):

var count = 30;
// throws an error
let count = 40;

例子2(不报错,在块中创建一个局部变量count,屏蔽了全局count直到从块中出来):

var count = 30;
if (condition) {
    // doesn't throw an error
    let count = 40;
    // more code
}

const声明,不提升,不可重复声明。声明的同时必须初始化,不可更改。

但是const声明的对象属性值是可以修改的,只是绑定不能修改。
例子:

const person = {
    name: "Nicholas"
};
// works
person.name = "Greg";
// throws an error
person = {
    name: "Greg"
};

暂存死区(Temporal Dead Zone,TDZ)

let和const声明的变量只能在声明之后调用。在声明之前引用会报引用错误,即使是用typeof之类的安全操作也不行。
例子:

if (condition) {
    console.log(typeof value);  // throws an error
    let value = "blue";
}

当JS引擎看到一个即将执行的代码块时,对var声明的变量做声明提升,而对let和var声明的变量则将声明放到一个暂存死区,任何在之前尝试读取TDZ中变量的操作都会导致运行时错误。直到执行流到let和var的定义,相应变量才从TDZ移除。
但是下面的例子不会报错,因为引用变量时它不在TDZ,即使没有也只是返回undefined。
例子:

console.log(typeof value);     // "undefined"
if (condition) {
    let value = "blue";
}

TDZ只是区块绑定的一个特别方面。另外一个在于循环当中。

循环中的区块绑定

在for循环中使用let声明的变量,在每次循环事都绑定了不同的变量。例子:

var funcs = [];
for (let i = 0; i < 10; i++) {
    funcs.push(function() {
        console.log(i);
    });
}
funcs.forEach(function(func) {
    func();     // outputs 0, then 1, then 2, up to 9
})

如果是var声明的i,那输出结果就会是10个10,只能使用IIFE来解决。对于for in和for of同样适用。例子:

var funcs = [],
    object = {
        a: true,
        b: true,
        c: true
    };
for (let key in object) {
    funcs.push(function() {
        console.log(key);
    });
}
funcs.forEach(function(func) {
    func();     // outputs "a", then "b", then "c"
});

如果是var key in object的话输出回事3个c。
let在for循环中的这个特性是ES6特别制定的,和变量提升无关。
对于const,在for循环中会报错,因为声明的变量不可修改,但在for in和for of中表现和let一致。例子:

var funcs = [];
// throws an error after one iteration
for (const i = 0; i < 10; i++) {
    funcs.push(function() {
        console.log(i);
    });
}

全局区块绑定

使用let和const声明的全局变量不会绑定到window的属性,但使用var声明的全局变量会绑定到window的属性。
例子:

// in a browser
let RegExp = "Hello!";
console.log(RegExp);                    // "Hello!"
console.log(window.RegExp === RegExp);  // false
const ncz = "Hi!";
console.log(ncz);                       // "Hi!"
console.log("ncz" in window);           // false

最佳实例

声明变量尽量使用const,除非你确定需要修改才使用let。

推荐阅读更多精彩内容

  • 块级绑定 let 声明 var 声明变量存在变量提升。 let 声明的语法与var的语法一致。 let声明会将变量...
    云彩上的翅胖阅读 191评论 0 0
  • 块级绑定:变量在块级作用域中的声明绑定形式。 块级绑定新的最佳实践 总结:默认情况下使用 const 、并且只在...
    M4不会点AWM不会顺阅读 191评论 0 0
  • let 命令 块级作用域 const 命令 顶层对象的属性 global 对象 let 命令 基本用法 ES6 新...
    嘉奇呦_nice阅读 1,489评论 0 2
  • 前言:块绑定 在传统意义上,变量声明工作的方式在Js一直是棘手的编程部分,在大多数基于C语言的编程语言中,变量(或...
    拾谷阅读 85评论 0 0
  • 本文属个人笔记,不做详解,仅供参考! let命令 基本用法 ES6 新增了let命令,用来声明变量。它的用法类似于...
    R_yan阅读 27,501评论 6 18