JavaScript - 函數提升:初學者指南
你好,未來的JavaScript大師!今天,我們將要深入探索JavaScript的一個讓新手上當的迷人特徵:函數提升。不要擔心這聽起來有些神秘——在這堂課結束時,你將會像專家一樣提升函數!
什麼是函數提升?
在我們深入細節之前,先來個簡單的定義:
函數提升是JavaScript中的一種行為,在代碼執行之前,函數聲明會被移到它們作用域的頂部。
現在,我知道你們在想什麼:"但是老師,這到底是什麼意思?"讓我們用一些例子來剖析它,好嗎?
示例 1:神奇出現的函數
sayHello(); // 這可以正常工作!
function sayHello() {
console.log("Hello, world!");
}
如果你是編程新手,現在可能會感到困惑。你會問:"我們怎麼能在定義函數之前調用它?"親愛的學生們,這就是函數提升的魔法!
在這個例子中,JavaScript將整個sayHello
函數提升到其作用域的頂部。所以,背後的代碼就像這樣:
function sayHello() {
console.log("Hello, world!");
}
sayHello(); // 现在這更有道理了,對吧?
示例 2:兩個函數的故事
讓我們來點刺激的,再看另一個例子:
greeting("John"); // 輸出:"Hello, John!"
farewell("John"); // 錯誤:farewell不是一個函數
function greeting(name) {
console.log("Hello, " + name + "!");
}
var farewell = function(name) {
console.log("Goodbye, " + name + "!");
};
在這兩個函數的故事中,我們看到了不同的行為。由於提升,greeting
函數在被調用之前可以正常工作。但是可憐的farewell
會拋出錯誤。為什麼?因為只有變量聲明var farewell
被提升,而不是函數賦值。
函數提升的規則
現在我們已經看到了函數提升的實際運作,讓我們來制定一些基本規則:
- 函數聲明會被完全提升。
- 變量聲明會被提升,但不是它們的賦值。
- 函數表達式(當你將函數賦值給一個變量)不會被提升。
讓我們用更多的例子來探索這些規則!
示例 3:聲明與表達式
// 這可以工作
hello();
function hello() {
console.log("Hello from a function declaration!");
}
// 這不能工作
goodbye(); // 錯誤:goodbye不是一個函數
var goodbye = function() {
console.log("Goodbye from a function expression!");
};
在這裡,hello
是一個函數聲明,所以它被完全提升。但是goodbye
是一個函數表達式,所以只有var goodbye
部分被提升,函數本身沒有。
JavaScript 變量提升
既然我們已經討論了函數提升,那麼我們快速看一下變量提升。這是一個相關的概念,理解它非常重要。
示例 4:神秘的未定義
console.log(x); // 輸出:undefined
var x = 5;
console.log(x); // 輸出:5
在這個例子中,變量x
的聲明被提升,但它的賦值沒有。所以第一次console.log
輸出undefined
,而第二次顯示賦值的值。
示例 5:Let 和 Const - 新來的 kids
console.log(a); // ReferenceError: 不能在初始化之前訪問'a'
let a = 10;
console.log(b); // ReferenceError: 不能在初始化之前訪問'b'
const b = 20;
隨著ES6中let
和const
的引入,我們得到了新的行為。這些聲明被提升,但未被初始化。這創造了"暫時死區",在這個區域內你不能訪問變量。
實際含義和最佳實踐
現在我們理解了提升是如何工作的,這對我們開發者來說意味著什麼?
-
始終在你們的作用域頂部聲明變量。 這會讓你的代碼更清晰,並防止意外的行為。
-
對於你們想在代碼中全程使用的函數,使用函數聲明。 它們的提升行為可以是有益的。
-
對於函數表達式要謹慎。 記住,它們不像函數聲明那樣被提升。
-
當有疑問時,一起聲明和初始化。 這消除了關於變量值的任何模糊性。
-
考慮使用
let
和const
而不是var
。 它們提供了更可預期的作用域行為。
下面是一個總結不同聲明提升行為的表格:
聲明類型 | 提升了嗎? | 初始化了嗎? |
---|---|---|
函數聲明 | 是 | 是 |
var | 是 | 未定義 |
let | 是 | 否(TDZ) |
const | 是 | 否(TDZ) |
函數表達式 | 否 | 否 |
結論
這就是它,我正在成長的程序员!我們已經解開了JavaScript中函數提升的謎題。記住,理解這些概念不僅僅是關於知道規則——這是關於寫出更乾淨、更可預測的代碼。
在你們的JavaScript旅程中,你將會遇到更多迷人(有時候也會讓人困惑)的特性。但是不要氣餒!每次你學到新東西,你都是成為JavaScript忍者更近一步。
持續練習,持續編碼,最重要的是,持續提問。畢竟,唯一愚蠢的問題是那個你沒有問的問題!
下次見,快樂編程!
Credits: Image by storyset