JavaScript 中的提升
提升是一種行為,其中變數和函數聲明在先前被移動(或「提升」)到其包含範圍(全域範圍或函數範圍)的頂部程式碼被執行。這意味著您可以在程式碼中實際聲明變數和函數之前使用它們。
變數提升
變數
- 用 var 宣告的變數被提升到其作用域的頂部,但它們的值直到程式碼中發生賦值的點才被初始化。
console.log(x); // undefined
var x = 5;
console.log(x); // 5
讓和常數
- 用 let 和 const 宣告的變數也會被提升,但會被放置在「臨時死區」中,直到到達它們的宣告為止。在聲明之前訪問它們將導致引用錯誤。
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 10;
// block scope
{
let x = 5;
}
console.log(x); // ReferenceError: x is not defined
函數提升
傳統功能
- 函數宣告被完全提升,這意味著宣告和函數體都被移動到作用域的頂端。這允許您在程式碼中聲明函數之前調用該函數。
sayHello(); // "Hello!"
function sayHello() {
console.log("Hello!");
}
- 相反,函數表達式(其中將函數分配給變數)僅作為變數提升,因此在初始化變數之前調用它們將導致未定義或類型錯誤。
greet(); // TypeError: greet is not a function
var greet = function () {
console.log("Hi!");
};
greet(); // ReferenceError: Cannot access 'one' before initialization
let greet = function () {
console.log("Hi!");
};
箭頭功能
- 相反,函數表達式(其中將函數分配給變數)僅作為變數提升,因此在初始化變數之前調用它們將導致未定義或類型錯誤。
greet(); // TypeError: greet is not a function
var greet = () => {
console.log("Hi!");
};
greet(); // ReferenceError: Cannot access 'one' before initialization
let greet = function () {
console.log("Hi!");
};
暫時死區 (TDZ)
臨時死區 (TDZ) 對於使用 let 和 const 宣告的變數存在,因為 JavaScript 旨在防止您在宣告和初始化這些變數之前存取它們。
為什麼 var 和 let、const 在提升中表現不同
- 這是因為JavaScript的歷史演變。
- 最初,JavaScript 是為非開發人員的使用者設計的,JavaScript 的主要核心用途是為網頁添加小型互動元素。
- 所以 var 只支援函數作用域。同樣在那個時候,還沒有塊作用域。
- 但在 JavaScript 的後期發展中,使用 var 和修復 bug 變得更加複雜。
- 因此,為了讓 JavaScript 與其他現代語言競爭,增加了更多功能,如 let、const、箭頭函數、ES6 方法等。
為什麼 var 不像 let 和 const 那樣更新
- 這是因為向後相容。
- 當時,JavaScript已被許多企業廣泛使用,因此更新或變更現有功能會導致程式碼庫的破壞。
- 因此,單獨添加了現代功能。
常見面試問題
- JavaScript 中什麼是提升?
- JavaScript 中什麼是提升的,什麼不是?
- var、let 和 const 在提升方面有什麼不同?
- JavaScript 中的臨時死區 (TDZ) 是什麼?
- 您能解釋一下使用函數宣告與函數表達式進行提升嗎?
- ES6模組中的提升是什麼?
- 為什麼我們應該避免在現實程式碼中依賴提升?
概括
- 提升是 JavaScript 中的預設行為,其中變數和函數宣告在編譯階段被移到各自作用域的頂部。
- 提升僅適用於使用 var 和傳統函數宣告的變量,不適用於 let、const 和箭頭函數。
- 只有函數聲明被提升,所以傳統函數可以工作,但如果函數被分配給變量,則在定義之前它是不可調用的。
- 之所以var和傳統函數被提升,而let、const和箭頭函數沒有被提升,是因為在初期,JavaScript主要用於小型UI交互。
- 但後來,隨著 JavaScript 被廣泛用於企業建立應用程序,僅在全局範圍內修復錯誤變得更加困難。
- 因此,在未來的更新中,會解決更多安全性問題。
- 此外,更新現有功能會破壞程式碼庫,因此單獨新增功能。