變量提升(Hoisting) 是 JavaScript 引擎在代碼執行前的一個特殊行為,它會將變量聲明和函數聲明自動移動到當前作用域的頂部。但需要注意的是,只有聲明會被提升,賦值操作不會提升。
??核心概念??
-
變量聲明提升(僅
var
和函數參數):
? 用var
聲明的變量會被提升到作用域頂部,但賦值留在原地。? 用
let
和const
聲明的變量也會被提升,但不會初始化,導致暫時性死區(TDZ)。 -
函數聲明提升:
? 函數聲明(非函數表達式)整體被提升,包括函數體。
??示例代碼??
var
的變量提升
javascript
復制
console.log(a); // 輸出 undefined(變量聲明被提升,但未賦值)
var a = 10;
等價于:
javascript
復制
var a; // 聲明提升到頂部
console.log(a); // undefined
a = 10; // 賦值留在原地
let
和const
的暫時性死區
javascript
復制
console.log(b); // 報錯:Cannot access 'b' before initialization
let b = 20;
雖然 b
的聲明被提升,但在聲明前訪問會觸發錯誤。
- 函數聲明提升
javascript
復制
foo(); // 輸出 "Hello"
function foo() {console.log("Hello");
}
等價于:
javascript
復制
function foo() { // 函數聲明整體提升console.log("Hello");
}
foo();
??注意事項??
-
函數表達式不會被提升:
javascript
復制
bar(); // 報錯:bar is not a function var bar = function() { /* ... */ };
此時
bar
是變量,提升的是變量聲明(值為undefined
)。 -
函數聲明優先級高于變量聲明:
javascript
復制
console.log(typeof a); // 輸出 "function" var a = 3; function a() {}
??為什么會有變量提升???
JavaScript 引擎在執行代碼前會經歷兩個階段:
- 編譯階段:解析代碼,提升變量和函數聲明。
- 執行階段:逐行執行代碼。
??如何避免問題???
- 優先使用
let
和const
:避免var
的隱式全局變量和提升問題。 - 聲明變量時先寫后用:
javascript
復制
let c = 30; console.log(c); // 正常輸出 30
- 使用嚴格模式(
"use strict"
):禁止意外的全局變量。
??總結??
? 變量提升是 JavaScript 的歷史遺留特性,可能導致意外行為。
? var
會提升聲明但初始化為 undefined
,let
/const
存在暫時性死區。
? 函數聲明整體提升,函數表達式不會被提升。
? 現代開發中推薦使用 let
/const
和函數表達式(箭頭函數)來規避問題。