提升到底是什么?

2025-06-07

提升到底是什么?

作为一名 JavaScript 开发者,你时常会遇到“代码提升”这个术语。你知道什么是代码提升,以及它是如何运作的吗?如果你知道的话,那就让我们来一探究竟吧。在本文中,我们将探讨什么是代码提升,它是如何运作的,以及哪些代码会被提升。

什么是提升?

要理解什么是提升,我们需要了解一些概念。

首先,人们普遍认为 JavaScript 不是编译型语言。事实上,JavaScript 引擎会在执行之前对代码进行编译。

其次,我们需要了解在获取变量值时可能发生的一些错误类型。它们是引用错误、类型错误和未定义错误。ReferenceError当调用未声明的变量时发生。TypeError当值不是预期类型时发生。undefined当调用的变量未赋值或未初始化时返回。掌握了这些基础知识后,我们现在可以理解什么是提升。如果您不理解这些,本文中的示例将帮助您更好地理解它。

那么什么是提升?

提升 (Hoisting) 是 JavaScript 中的一个概念,指变量和函数声明在代码执行前的编译阶段被放入内存中。这使得这些声明看起来好像被移动到了其作用域的顶部,从而使它们在该作用域的任何位置都可用。请注意,这实际上并没有发生。

让我们通过一个例子来更好地理解这一点。

console.log(a)

var a = 2;
Enter fullscreen mode Exit fullscreen mode

看看上面的代码,你觉得结果会是什么?2、undefined 还是 Reference 错误?打开浏览器控制台并运行代码。你得到了什么?

我明白了undefined。我相信你也明白了。你可能会期待一个引用错误,因为你在变量声明之前就调用了它。但这并没有发生,因为变量声明被提升到了代码的顶部。所以在执行过程中,代码是这样执行的。

var a;

console.log(a); //undefined

a = 2;

Enter fullscreen mode Exit fullscreen mode

有道理吧?注意,只有声明会被引擎提升,赋值不会被提升。变量声明会被提升,并用 初始化undefined。这就是为什么我们得到的是undefined而不是 2,因为赋值操作仍然在赋值的位置。

另外,请注意,变量提升是针对每个作用域的。因此,如果我们在函数内声明变量,该变量将在函数作用域内可用。如果我们在函数外声明变量,它将在全局作用域内可用。如果我们在声明变量的作用域之外使用变量,它将返回Reference Error。例如,如果我们执行下面的代码,就会出现引用错误。

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

function a() {
    var b = 2
}
Enter fullscreen mode Exit fullscreen mode

说到函数,所有函数都会被提升吗?我觉得我们需要一个标题来说明哪些函数会被提升。

哪些内容会被提升

函数声明会被提升。因此,我们可以在代码中声明函数之前调用它。

foo(2); // 2

function foo(a) {
    console.log(a)
}

Enter fullscreen mode Exit fullscreen mode

函数表达式不会被提升。如果我们在将函数赋值给函数表达式之前调用它,则会得到TypeError

foo(2); // Uncaught TypeError: foo is not a function

var foo = function (a) {
    console.log(a)
}

Enter fullscreen mode Exit fullscreen mode

foo用 初始化undefined,因此将变量作为函数调用会导致类型错误。

那么 ES6 变量let和呢const?它们也会被提升吗?

是的,它们是,但它们不像undefined那样被初始化var,而是保持未初始化状态。如果我们在它们赋值之前使用它们,它们会返回ReferenceError而不是undefined

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

let b = 2;

Enter fullscreen mode Exit fullscreen mode

同样的事情const

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

const a = 2;
Enter fullscreen mode Exit fullscreen mode

需要注意的是,const如果没有初始化,就无法声明变量。因此,下面的代码会抛出另一种错误。

console.log(a)

const a;
a = 4;

//Uncaught SyntaxError: Missing initializer in const declaration
Enter fullscreen mode Exit fullscreen mode

什么先被提升?变量还是函数?

我们已经看到变量和函数声明都会被提升。它们哪个会先被提升呢?让我们来做个小练习​​。看看下面的代码,你期望打印什么?字符串还是函数?猜一下,然后在控制台中尝试一下。

console.log(typeof foo);

var foo = 'hello';

function foo() {
    console.log(4);
}

Enter fullscreen mode Exit fullscreen mode

结果如何?我确信结果会是function……。这证明了两点:

  1. 函数优先被提升,这就是为什么尽管变量在字符串之前声明,但 JavaScript 引擎仍然将其解释为函数。实际上,这就是引擎执行代码的方式。
function foo() {
    console.log(4);
}

console.log(typeof foo); //function

foo = 'hello';
Enter fullscreen mode Exit fullscreen mode

如果 console.log 语句位于变量声明之后,结果将会是string这样的。请注意,变量声明(与函数 重复)被忽略了。这就引出了第二点。

  1. 使用相同的变量名进行重复声明是个坏主意。重复的声明会被 JavaScript 引擎忽略,这通常会导致令人困惑的结果。

让我们回顾一下本章讨论的内容。

审查

  1. 提升是指变量和函数声明在执行过程中似乎移动到代码顶部的概念。这是因为变量和函数声明在编译阶段会被处理。

  2. 所有变量均被提升。var被提升并用 初始化undefinedletconst被提升但未初始化。

  3. 函数声明会被提升,但函数表达式则不会。

  4. 在编译阶段,函数声明在变量声明之前提升。

感谢您的阅读。

文章来源:https://dev.to/sarah_chima/what-is-hoisting-anyway-49a2
PREV
Git [脚本] 可能有用的别名
NEXT
您最喜欢的学习资源是什么?