ES6 let & const

最后更新:
阅读次数:
  • let 声明了一个块级域的局部变量
  • const 声明一个块级域的只读的常量

let 和 const 共有的特性

  • 不存在变量提升

就变量提升这个说法来说,国外也有人说 letconst 也存在变量提升,看链接:Are variables declared with let or const not hoisted in ES6?

但是我还是觉得直接说 letconst 不存在变量提升比较容易理解。

console.log(a); // undefined
console.log(b); // Uncaught ReferenceError: b is not defined(…)

var a = 1;
let b = 2; // 或 const b = 2;
  • 都存在暂时性死区

在代码块内,使用 let const 命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区(temporal dead zone,简称 TDZ)。

if (true) {
// TDZ开始
tmp = "abc"; // ReferenceError
console.log(tmp); // ReferenceError

let tmp; // TDZ结束
console.log(tmp); // undefined

tmp = 123;
console.log(tmp); // 123
}

ES6 规定暂时性死区和 letconst 语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。

  • 同一作用域内,不允许重复声明
// test 1
{
let a = 1;
var a = 2; // Uncaught SyntaxError: Identifier 'a' has already been declared
}

// test 2
{
const b = "const";
let b; // // Uncaught SyntaxError: Identifier 'b' has already been declared
}
  • 与顶层对象的属性脱钩

letconst 声明的全局变量,不属于顶层对象的属性。

var a = 1;
let b = 2;
const c = 3;
console.log(window.a); // 1
console.log(window.b); // undefined
console.log(window.c); // undefined

块级作用域

ES6 引入了块级作用域。

块级作用域的出现,实际上使得获得广泛应用的立即执行匿名函数(IIFE)不再必要了。

// IIFE写法
(function () {
var tmp = ...;
...
}());

// 块级作用域写法
{
let tmp = ...;
...
}

ES6 规定,允许在块级作用域之中声明函数

我做了一个测试:在 Chrome 54.0 的控制台下,分别测试了下面代码(注意:第一次测试完后,请刷新页面,否则测试无效):

// 在严格模式下调用 f1 函数
"use strict";
{
function f1() {
console.log("f1 is invoking!");
}
}
f1(); // 报错,Uncaught ReferenceError: f1 is not defined(…)

// 在普通模式下调用 f1 函数
{
function f1() {
console.log("f1 is invoking!");
}
}
f1(); // f1 is invoking!

所以,考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

// 函数声明语句
{
let a = "secret";
function f() {
return a;
}
}

// 函数表达式
{
let a = "secret";
let f = function() {
return a;
};
}

const 需要注意的地方

  • const 声明的常量不能对其进行赋值,否则报错
const PI = 3.1415926;
PI = 3.14; // Uncaught TypeError: Assignment to constant variable.(…)
  • const 必须在声明变量的同时并进行初始化,否则报错
const a; // Uncaught SyntaxError: Missing initializer in const declaration
  • 对于用 const 声明的复合类型的变量(比如一个对象),和 var 一样,变量名不指向数据,而是指向数据所在的地址,只不过这个变量的值(对象的地址)不能变而已。所以可以自由更改复合类型的数据。所以,请慎重将对象声明为常量。

要是你想冻结一个对象,使用 Object.freeze(obj)

const obj = {};
console.log(obj); // Object {}
obj.name = "percy";
console.log(obj); // Object {name: "percy"}
obj = {}; // 报错,Uncaught TypeError: Assignment to constant variable.(…)

// 清除上面的错误,继续上面的代码
Object.freeze(obj); // 冻结 obj
obj.age = "21"; // 默认忽略更改,严格模式下报错
console.log(obj); // Object {name: "percy"}

参考资料