var 声明与变量提升

使用 var 关键字声明的变量,无论其实际声明位置在何处,都会被视为声明于所在函数的顶 部(如果声明不在任意函数内,则视为在全局作用域的顶部)。这就是所谓的变量提升( hoisting )。为了说明变量提升的含义,请参考如下函数定义:
深入理解ES6

如果你不太熟悉 JS ,或许会认为仅当 condition 的值为 true 时,变量 value 才会被创 建。但实际上,value 无论如何都会被创建。 JS 引擎在后台对 getValue 函数进行了调整, 就像这样:
深入理解ES6
value 变量的声明被提升到了顶部,而初始化工作则保留在原处。这意味着在 else 分支内 value 变量也是可访问的,此处它的值会是 undefined ,因为它并没有被初始化。

块级声明

块级声明也就是让所声明的变量在指定块的作用域外无法被访问。块级作用域(又被称为词 法作用域)在如下情况被创建: 1. 在一个函数内部 2. 在一个代码块(由一对花括号包裹)内部 块级作用域是很多类 C 语言的工作机制, ES6 引入块级声明,是为了给 JS 添加灵活性以及 与其他语言的一致性。

let 声明

let 声明的语法与 var 的语法一致。你基本上可以用 let 来代替 var 进行变量声明,但 会将变量的作用域限制在当前代码块中(其他细微差别会在稍后讨论)。由于 let 声明并不 会被提升到当前代码块的顶部,因此你需要手动将 let 声明放置到顶部,以便让变量在整个 代码块内部可用。这里有个范例:
深入理解ES6
如你所愿,这种写法的 getValue 函数的行为更接近其他类 C 语言。由于变量 value 声明 使用的是 let 而非 var ,该声明就没有被提升到函数定义的顶部,因此变量 value 在 if 代码块外部是无法访问的;并且在 condition 的值为 false 时,该变量是永远不会被声 明并初始化的。

禁止重复声明

如果一个标识符已经在代码块内部被定义,那么在此代码块内使用同一个标识符进行 let 声 明就会导致抛出错误。例如:
深入理解ES6
在本例中, count 变量被声明了两次:一次使用 var ,另一次使用 let 。因为 let 不能 在同一作用域内重复声明一个已有标识符,此处的 let 声明就会抛出错误。另一方面,在嵌 套的作用域内使用 let 声明一个同名的新变量,则不会抛出错误,以下代码对此进行了演示:
深入理解ES6
此处的 let 声明并没有抛出错误,这是因为它在 if 语句内部创建了一个新的 count 变 量,而不是在同一级别再次创建此变量。在 if 代码块内部,这个新变量会屏蔽全局的 count 变量,从而在局部阻止对于后者的访问。

使用 const

声明对象 const 声明会阻止对于变量绑定与变量自身值的修改,这意味着 const 声明并不会阻止对 变量成员的修改。例如:
深入理解ES6
此处 person 在初始化时被绑定了带有一个属性的对象。修改 person.name 是可能的,并不 会抛出错误,因为该操作只修改了 person 对象的成员,而没有修改 person 的绑定值。当 代码试图为 person 对象自身赋值时(这会改变变量绑定),就会导致错误。 const 在变量 上的微妙工作机制容易导致误解,但只需记住: const 阻止的是对于变量绑定的修改,而不 阻止对成员值的修改。

暂时性死区

使用 let 或 const 声明的变量,在达到声明处之前都是无法访问的,试图访问会导致一个 引用错误,即使在通常是安全的操作时(例如使用 typeof 运算符),也是如此。示例如 下:
深入理解ES6
此处的 value 变量使用了 let 进行定义与初始化,但该语句永远不会被执行,因为声明之 前的那行代码抛出了一个错误。出现该问题是因为: value 位于被 JS 社区称为暂时性死区 ( temporal dead zone , TDZ )的区域内。该名称并未在 ECMAScript 规范中被明确命 名,但经常被用于描述 let 或 const 声明的变量为何在声明处之前无法被访问。本小节的 内容涵盖了暂时性死区所导致的声明位置的微妙之处,尽管这里使用的都是 let ,但替换为 const 也会有相同情况。

使用 let 或 const 声明的变量,若试图在定义位置之前使用它,无论如何都不能避免暂时 性死区。而且正如上例所演示的,这甚至影响了通常安全的 typeof 运算符。然而,你可以 在变量被定义的代码块之外对该变量使用 typeof ,尽管其结果可能并非预期。考虑以下代码:

深入理解ES6
当 typeof 运算符被使用时, value 并没有在暂时性死区内,因为这发生在定义 value 变 量的代码块外部。这意味着此时并没有绑定 value 变量,而 typeof 仅单纯返回了 “undefined” 。 暂时性死区只是块级绑定的一个独特表现,而另一个独特表现则是在循环时使用它。

相关文章: