3. JavaScript 中隐藏的提升(Hoisting)特性

57 阅读3分钟

JavaScript 中隐藏的提升(Hoisting)特性

关键字:提升、变量提升、变量声明、变量赋值、变量初始化、代码执行前、代码解析、当前作用域、暂时性死区、函数提升、函数表达式、函数声明、函数定义

Keywords: Hoisting, variable hoisting, variable declaration, variable assignment, variable initialization, before code execution, code parsing, current scope, temporary dead zone, function hoisting, function expression, function declaration, function definition

在 JavaScript 中,提升(Hoisting) 是指 变量声明函数声明 会在 代码执行前 被 “提升” 到 其 作用域的顶部

In JavaScript, hoisting means that variable declarations and function declartions are hoisted to the top of their scope before code execution.

这一特性 使得我们可以在 声明变量 或 函数 之前 使用它们。需要注意的是,只有声明会被提升,赋值不会被提升

This feature allows to use variables or functions before declaring them. It ist important to note that only declarations are hoisted, not assignments.

1 JavaScript 变量提升的概念

1.1 知识储备-了解变量的声明和赋值

要理解变量提升就要先知道,变量的 声明 和 赋值(初始化)。

To understand variable hoisting, you must first know the declaration and assignment (initialization) of variables.

变量的声明,就是使用 varletconst 关键字来 告诉 JS 引擎 该变量存在。初始化(赋值),就是 为该变量 赋一个具体的值

Variable declaration is to use var, let or const keywords to tell the JS engine that the variable exists. Initialization (assignment) is to assign a specific value to the variable.

1.2 变量提升

JavaScript 会在 代码执行前 解析 变量声明,并将其提升到 当前作用域顶部

JavaScript parses variable declarations before code execution and hoists them to the top of the current scope.

在使用 var 声明时,变量会被 默认初始化undefined。虽然 var 声明被提升,但它的 赋值操作 没有被提升 ,所以在赋值之前访问该变量,输出的的还是 undefined

When using var declaration, the variable will be initialized to undefined. Although the var declaration is hoisted, its assignment operation is not hoisted, so accessing the variable before the assignment will still output undefined.

console.log(myVar); // 输出 undefined,因为 myVar 被提升了,但未赋值,所以使用 默认值 undefined
var myVar = 10;
console.log(myVar); // 输出 10

// ----- 上面代码 等价于 下面代码------

var myVar;
console.log(myVar); // 输出 undefined
myVar = 10;
console.log(myVar); // 输出 10

letconst声明也会被提升,但它们 不会被 自动初始化undefined,在初始化之前 不能访问,处于 暂时性死区(TDZ)。

let and const declarations are also hoisted, but they are not automatically initialized to undefined and cannot be accessed before initialization, and are in the Temporal Dead Zone (TDZ).

console.log(myLet); // ReferenceError: Cannot access 'myLet' before initialization
let myLet = 20;

// ----- 上面代码 等价于 下面代码------

let myLet; // 提升,但不初始化
console.log(myLet); // 由于 TDZ 而报错
myLet = 20;

2 JavaScript 函数提升的概念

函数声明会被提升,并且 它 所在作用域最顶部就可以使用

The function declaration is also hoisted and becomes available from the top of its scope.

console.log(sayHello()); // 输出 "Hello!"

function sayHello() {
  return "Hello!";
}

// ----- 上面代码 等价于 下面代码------

function sayHello() {
  return "Hello!";
}

console.log(sayHello()); // 输出 "Hello!"

但如果使用 函数表达式,只有 变量声明 会被提升,而 函数定义 不会被提升,因此,在函数表达式定义之前 调用函数 会导致 undefined 错误。

But if you use function expressions, only variable declarations are hoisted, but function definitions are not hoisted, so calling a function before the function expression definition will result in an undefined error.

console.log(sayHi()); // TypeError: sayHi is not a function

var sayHi = function() {
  return "Hi!";
};

// ----- 上面代码 等价于 下面代码------

var sayHi;
console.log(sayHi()); // TypeError: sayHi is not a function
sayHi = function() {
  return "Hi!";
};