JavaScript 变量提升(Hoisting)

2025年4月16日 | 阅读 4 分钟

在 JavaScript 中,变量提升(hoisting)是一种内置行为,它可以在代码执行之前将函数、变量和类的声明移动到其作用域的顶部。

简而言之,变量提升是一种将 变量函数 的声明移到其各自作用域顶部的行为。它确保无论这些声明在作用域中的哪个位置出现,都可以在整个作用域中访问它们。

示例

立即执行

输出

undefined

说明

在此代码中,声明 var a 被提升到顶部,但 a 被初始化为 undefined。代码的输出将是 undefined。

为什么使用 JavaScript 变量提升?

我们使用 JavaScript 变量提升有以下几个原因:

易用性

JavaScript 中,通过使用变量提升,我们可以允许开发人员在使用函数之前就调用它们,这使得代码更具可读性和直观性。假设我们可以在源代码中定义函数之前就调用它。

函数声明作用域

在 JavaScript 中,函数声明会被完全提升,这意味着函数名和其实现都会被移动到作用域的顶部。这使得你可以在代码中的任何位置定义函数,并在作用域中的任何其他位置使用它们。

变量声明

变量声明也会被提升,但有一个细微的差别。只有变量名会被提升到作用域的顶部,而赋值语句会保留在原地。如果理解不当,这有时可能导致意外行为。

执行顺序

理解变量提升有助于我们作为开发人员预测变量和函数的执行顺序,从而可以避免代码中的错误和意外行为。

避免引用错误

在 JavaScript 中,借助变量提升,我们可以避免在使用变量或函数尚未声明时可能发生的引用错误。在其他编程语言中,在声明之前使用变量可能会导致错误,但 JavaScript 的变量提升机制允许代码仍按预期工作。

暂时性死区 (TDZ)

在 JavaScript 中,暂时性死区 (TDZ) 是变量提升中的一个重要概念。在代码执行期间,使用 letconst 声明的变量会被提升,但在此期间不可访问。

简而言之,即使由于变量提升,这些变量在概念上可在作用域中使用,但在代码中声明之前,你无法访问它们。如果你尝试在初始化之前引用变量,它将抛出一个 ReferenceError。

示例

立即执行

输出

ReferenceError: Cannot access 'a' before initialization

变量提升的类型

变量提升

JavaScript 中变量提升的行为取决于变量是使用 var、let 还是 const 声明的。

使用 var 的变量提升

在 JavaScript 中,当我们使用 var 关键字声明变量时,它会被提升到其当前作用域的顶部。

示例

立即执行

输出

undefined

说明

在上面的代码中,我们可以在声明变量 a 之前使用它。这是因为该变量被提升了,其默认值为 undefined。

使用 let 和 const 的变量提升

在 JavaScript 中,当使用 let 和 const 关键字声明变量时,它会被提升到其当前作用域的顶部。但是,当变量被提升时,它没有默认值。

示例

立即执行

输出

ReferenceError: Cannot access `demo` before initialization

说明

在此代码中,将发生错误,因为用 let 声明的变量在被提升时没有被分配任何默认值。

函数提升

在 JavaScript 中,函数提升是一种在函数声明之前调用该函数的技术。

示例

立即执行

输出

Hello, Denji!

说明

在此代码中,由于变量提升,我们可以先调用 demo() 函数,然后再声明它。

类提升

在 JavaScript 中,类会被提升,但它们在声明之前无法被访问,因为它们会停留在暂时性死区(Temporal Dead Zone),直到声明被执行。

示例

立即执行

输出

ReferenceError: Cannot access 'MyClass' before initialization

JavaScript 变量提升的特点

JavaScript 变量提升有一些关键特点,例如:

变量声明

在 JavaScript 中,当使用 var 声明变量时,它们会被提升到其作用域的顶部。但是,只有声明会被提升,初始化不会。这意味着可以在声明变量之前使用该变量,但直到为变量赋值之前,其值将为 undefined。

函数声明

在 JavaScript 中,函数声明会被完全提升,包括函数名和其实现。这允许你在代码中声明函数之前调用它。

函数表达式

在 JavaScript 中,函数表达式是将函数赋值给变量,而这些变量不会像函数声明那样被提升。在这种情况下,只有变量声明会被提升,函数赋值不会。

块级作用域

在 JavaScript 中,使用 let 和 const 声明的变量会被提升到其块级作用域的顶部,但与 var 不同的是,它们直到声明被评估后才会被初始化。这被称为“暂时性死区”。

结论

在 JavaScript 中,变量提升是一个重要的概念,它在编译阶段将变量和函数声明移到其作用域的顶部,从而允许在代码中实际声明之前使用变量和函数。