JavaScript的提升机制就像舞台剧的布景准备。在代码运行之前(在“创建阶段”),JavaScript会将所有声明提升到其作用域的顶部,就像舞台工作人员在幕布升起前将道具搬到指定位置一样。唯一的区别是,只有声明被提升,初始化并没有被提升。
根据ECMAScript规范,这种行为实际上是JavaScript在创建阶段创建所谓的“词法环境”的一部分。但让我们不要过于技术化,只需记住JavaScript会在运行代码之前对其进行“预扫描”。
var
提升<code class="language-javascript">console.log(x); // 输出:undefined var x = 5; console.log(x); // 输出:5</code>
在这个例子中,var x
声明被提升到作用域的顶部,但初始化x = 5
没有被提升。这就是为什么第一个console.log(x)
输出undefined
而不是抛出错误。变量x
存在,但它还没有被赋值。
let
和 const
的暂时性死区 (TDZ)<code class="language-javascript">console.log(y); // 抛出ReferenceError: Cannot access 'y' before initialization let y = 10; console.log(y); // 输出:10</code>
在这个例子中,let y
声明被提升,但是它在初始化行之前位于暂时性死区 (TDZ)。在初始化之前尝试访问y
会导致ReferenceError
。此行为与var
不同,var
在类似情况下只会返回undefined
。
这也包括使用
let
或const
声明的任何内容,当然也包括函数。
说到暂时性死区,这是let
和const
声明在初始化之前存在的地方。与var
在初始化之前访问时返回undefined
不同,这些现代声明会抛出错误。ECMAScript规范将此行为称为“暂时性死区语义”,但我称之为“JavaScript让我们诚实”。
<code class="language-javascript">function setupEventHandler() { handleClick(); // 可运行! const config = { debug: true, }; function handleClick() { if (config?.debug) { // 未定义! console.log("Debug mode"); } } } setupEventHandler();</code>
看到这里发生了什么吗?函数声明handleClick
被提升了,所以我们可以提前调用它。但是config
对象呢?它仍然留在它所在的位置。这就是为什么在handleClick
内部访问config
会给我们undefined
,我们试图在脚本准备好之前读取它。
类提升的工作方式不太一样。
<code class="language-javascript">const dog = new Animal(); // 抛出错误! class Animal { constructor() { this.type = "mammal"; } }</code>
虽然类被提升了,但在它们的定义被评估之前,它们仍然处于“暂时性死区”。这意味着在声明它们之前,你无法访问它们。
记住,声明被移动到顶部,但初始化保持不变。
以上是JavaScript提升 - 移动和停留什么的详细内容。更多信息请关注PHP中文网其他相关文章!