提升到底是什么?
作为一名 JavaScript 开发者,你时常会遇到“代码提升”这个术语。你知道什么是代码提升,以及它是如何运作的吗?如果你知道的话,那就让我们来一探究竟吧。在本文中,我们将探讨什么是代码提升,它是如何运作的,以及哪些代码会被提升。
什么是提升?
要理解什么是提升,我们需要了解一些概念。
首先,人们普遍认为 JavaScript 不是编译型语言。事实上,JavaScript 引擎会在执行之前对代码进行编译。
其次,我们需要了解在获取变量值时可能发生的一些错误类型。它们是引用错误、类型错误和未定义错误。ReferenceError
当调用未声明的变量时发生。TypeError
当值不是预期类型时发生。undefined
当调用的变量未赋值或未初始化时返回。掌握了这些基础知识后,我们现在可以理解什么是提升。如果您不理解这些,本文中的示例将帮助您更好地理解它。
那么什么是提升?
提升 (Hoisting) 是 JavaScript 中的一个概念,指变量和函数声明在代码执行前的编译阶段被放入内存中。这使得这些声明看起来好像被移动到了其作用域的顶部,从而使它们在该作用域的任何位置都可用。请注意,这实际上并没有发生。
让我们通过一个例子来更好地理解这一点。
console.log(a)
var a = 2;
看看上面的代码,你觉得结果会是什么?2、undefined 还是 Reference 错误?打开浏览器控制台并运行代码。你得到了什么?
我明白了undefined
。我相信你也明白了。你可能会期待一个引用错误,因为你在变量声明之前就调用了它。但这并没有发生,因为变量声明被提升到了代码的顶部。所以在执行过程中,代码是这样执行的。
var a;
console.log(a); //undefined
a = 2;
有道理吧?注意,只有声明会被引擎提升,赋值不会被提升。变量声明会被提升,并用 初始化undefined
。这就是为什么我们得到的是undefined
而不是 2,因为赋值操作仍然在赋值的位置。
另外,请注意,变量提升是针对每个作用域的。因此,如果我们在函数内声明变量,该变量将在函数作用域内可用。如果我们在函数外声明变量,它将在全局作用域内可用。如果我们在声明变量的作用域之外使用变量,它将返回Reference Error
。例如,如果我们执行下面的代码,就会出现引用错误。
console.log(b); //Uncaught ReferenceError: b is not defined
function a() {
var b = 2
}
说到函数,所有函数都会被提升吗?我觉得我们需要一个标题来说明哪些函数会被提升。
哪些内容会被提升
函数声明会被提升。因此,我们可以在代码中声明函数之前调用它。
foo(2); // 2
function foo(a) {
console.log(a)
}
函数表达式不会被提升。如果我们在将函数赋值给函数表达式之前调用它,则会得到TypeError
。
foo(2); // Uncaught TypeError: foo is not a function
var foo = function (a) {
console.log(a)
}
foo
用 初始化undefined
,因此将变量作为函数调用会导致类型错误。
那么 ES6 变量let
和呢const
?它们也会被提升吗?
是的,它们是,但它们不像undefined
那样被初始化var
,而是保持未初始化状态。如果我们在它们赋值之前使用它们,它们会返回ReferenceError
而不是undefined
。
console.log(b); //Uncaught ReferenceError: b is not defined
let b = 2;
同样的事情const
console.log(a);//Uncaught ReferenceError: a is not defined
const a = 2;
需要注意的是,const
如果没有初始化,就无法声明变量。因此,下面的代码会抛出另一种错误。
console.log(a)
const a;
a = 4;
//Uncaught SyntaxError: Missing initializer in const declaration
什么先被提升?变量还是函数?
我们已经看到变量和函数声明都会被提升。它们哪个会先被提升呢?让我们来做个小练习。看看下面的代码,你期望打印什么?字符串还是函数?猜一下,然后在控制台中尝试一下。
console.log(typeof foo);
var foo = 'hello';
function foo() {
console.log(4);
}
结果如何?我确信结果会是function
……。这证明了两点:
- 函数优先被提升,这就是为什么尽管变量在字符串之前声明,但 JavaScript 引擎仍然将其解释为函数。实际上,这就是引擎执行代码的方式。
function foo() {
console.log(4);
}
console.log(typeof foo); //function
foo = 'hello';
如果 console.log 语句位于变量声明之后,结果将会是string
这样的。请注意,变量声明(与函数 重复)被忽略了。这就引出了第二点。
- 使用相同的变量名进行重复声明是个坏主意。重复的声明会被 JavaScript 引擎忽略,这通常会导致令人困惑的结果。
让我们回顾一下本章讨论的内容。
审查
-
提升是指变量和函数声明在执行过程中似乎移动到代码顶部的概念。这是因为变量和函数声明在编译阶段会被处理。
-
所有变量均被提升。
var
被提升并用 初始化undefined
。let
和const
被提升但未初始化。 -
函数声明会被提升,但函数表达式则不会。
-
在编译阶段,函数声明在变量声明之前提升。
感谢您的阅读。
文章来源:https://dev.to/sarah_chima/what-is-hoisting-anyway-49a2