在本教程中,您将了解 JavaScript 变量提升及其背后的工作原理。

JavaScript 变量提升简介

当 JavaScript 引擎执行 JavaScript 代码时,它会创建全局执行上下文。全局执行上下文有两个阶段:

  • 创建
  • 执行

在创建阶段,JavaScript 引擎将变量和函数声明移动到代码的顶部。这在 JavaScript 称为变量提升。

变量提升

变量提升意味着 JavaScript 引擎将变量声明移动到脚本的顶部。例如,下面的示例声明 counter 变量并将其值初始化为 1

console.log(counter); // 👉 undefined
var counter = 1;

在这个例子中,我们在声明之前引用 counter 变量。

但是,第一行代码不会导致错误。原因是 JavaScript 引擎将变量声明移动到脚本的顶部。

从技术上讲,代码在执行阶段看起来如下所示:

var counter;

console.log(counter); // 👉 undefined
counter = 1;

在全局执行上下文的创建阶段,JavaScript 引擎将 counter 变量放入内存并将其值初始化为 undefined.

let 关键字

下面用 let 关键字声明 counter 变量:

console.log(counter);
let counter = 1;

JavaScript 将会抛出下面的错误:

"ReferenceError: Cannot access 'counter' before initialization

错误信息说明 counter 变量已经在堆内存中。但是,它还没有被初始化。

在幕后,JavaScript 引擎会提升使用let关键字声明的变量。但是,它不会初始化 let 声明的变量。

请注意,如果您访问一个不存在的变量,JavaScript 将抛出一个不同的错误:

console.log(alien);
let counter = 1;

这是错误:

"ReferenceError: alien is not defined

函数提升

与变量一样,JavaScript 引擎也会提升函数声明。这意味着 JavaScript 引擎还将函数声明移动到脚本的顶部。例如:

let x = 20,
  y = 10;

let result = add(x, y); 
console.log(result); // 👉 30

function add(a, b) {
  return a + b;
}

输出:

30

在这个例子中,我们在定义 add() 函数之前调用 add() 函数。上面的代码等同于以下代码:

function add(a, b){
    return a + b;
}

let x = 20,
    y = 10;

let result = add(x,y);
console.log(result); // 👉 30

在上下文的创建阶段,JavaScript 引擎将 add() 函数声明放在堆内存中。准确地说,JavaScript 引擎创建一个 Function 类型的对象和一个引用 add 函数对象的函数引用。

函数表达式

以下示例将 add 函数由普通函数更改为函数表达式:

let x = 20,
    y = 10;

let result = add(x,y); // ❌ Uncaught ReferenceError: add is not defined
console.log(result);

let add = function(x, y) {
    return x + y;
}

如果执行代码,会出现如下错误:

Uncaught ReferenceError: add is not defined

在全局执行上下文的创建阶段,JavaScript 引擎在内存中创建 add 变量并将其值初始化为 undefined

执行以下代码时,addundefined,因此,它不是函数:

let result = add(x,y);

仅在全局执行上下文的执行阶段分配将匿名函数分配给  add 变量。

箭头函数

下面示例将 add 函数表达式更改为箭头函数

let x = 20,
    y = 10;

let result = add(x,y); // ❌ Uncaught ReferenceError: add is not defined
console.log(result);

let add = (x, y) => x + y; 

该代码还抛出与函数表达式示例相同的错误,因为箭头函数是用于定义函数表达式的语法糖。

Uncaught ReferenceError: add is not defined

与函数表达式类似,箭头函数不会提升。

结论

JavaScript 提升发生在上下文的创建阶段,它将变量和函数声明移动到脚本的顶部。

JavaScript 引擎提升使用 let 关键字声明的变量,但不会将它们初始化。使用 var关键字声明的变量也一样。

JavaScript 引擎不会提升函数表达式和箭头函数。