原文地址:https://dev.to/bhagatparwinder/hoisting-in-javascript-2aj2
什么是提示?
JavaScript 中的提升允许你在变量和函数声明之前使用它们。
函数提升
console.log(helloWorld()); // Hello World
console.log(multiplyNumbers(10, 5)); // 50
function helloWorld() {
return "Hello World";
}
function multiplyNumbers(a, b) {
return a * b;
}
如你所见,我在两个函数声明之前使用了它们并且 JavaScript 没有报错。打印出了预期的结果。使用函数之前先声明是一个好习惯。
var 声明变量提升
console.log(age); // undefined
console.log(foo); // Reference Error: foo is not defined
var age = 10;
我可以在变量声明之前使用它。打印出了 undefined,但并没有抛出错误。和打印 foo 相比,你会看到那条语句抛出了一个错误。
let 和 const 声明变量提示
let 和 const 声明的变量也会提升,但并不像 var 声明的那样默认初始化一个默认值 undefined。在初始化之前读取通过 let 或 const 声明的变量则会抛出错误。
console.log(num); // Throws ReferenceError exception as the variable value is uninitialized
let num = 6; // Initialization
注意,代码的执行顺序起关键作用而不是代码在文件中的书写顺序。在任何读取它的代码之前初始化就不会有报错。
这里加一些 TDZ(Temporal dead zone)的内容,TDZ 是指从块级作用域的开始到变量声明结束:
{ // TDZ starts at beginning of scope
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2; // End of TDZ (for foo)
}
之所以称为“暂时”,那是因为区域是根据代码的执行顺序(时间)而不是代码的书写顺序(位置)。例如:下面例子可以正常工作,即使函数在 let 声明的变量之前使用它,这个函数已经出了 TDZ 的范围。
{
// TDZ starts at beginning of scope
const func = () => console.log(letVar); // OK
// Within the TDZ letVar access throws `ReferenceError`
let letVar = 3; // End of TDZ (for letVar)
func(); // Called outside TDZ!
}
提升的警告
为什么没有打印 age 的值呢?
JavaScript 只提升声明,并不提升初始化。
就像例子中的 age ,只提升了声明并没有把值赋值给它。由于只提升了声明这个原则,若例子中是函数表达式你则无法使用提升来使用它。
console.log(helloWorld()); // helloWorld is not defined
console.log(multiplyNumbers(10, 5));
const helloWorld = function () {
return "Hello World";
}
const multiplyNumbers = function (a, b) {
return a * b;
}
更多参考 MDN。