初學者指南:深入了解 JavaScript 中的「一等公民」概念
更新日期: 2025 年 1 月 23 日
本文為 JavaScript 高階函數系列文,第 1 篇
在學習 JavaScript 的過程中,你可能會遇到「一等公民」(First-Class Citizens 或 First-Class Functions)這個術語。
它描述了 JavaScript 中的一個重要特性——函式(Function)在這個語言中被視為「一等公民」。
這意味著函式可以像其他數據類型(如數字、字串、物件等)一樣被使用和操作。
本文將為新手介紹「一等公民」的概念,並具體說明 JavaScript 如何處理函式作為「一等公民」。
什麼是一等公民?
一等公民的定義
在程式設計中,若一個語言中的某種元素能夠像其他基本數據類型一樣被操作,則該元素被稱為「一等公民」。
具體來說,一個「一等公民」應具備以下能力:
- 可以作為變數的值賦值給其他變數。
- 可以作為參數傳遞給其他函式。
- 可以作為函式的返回值返回。
- 可以存儲在資料結構(如陣列、物件)中。
在 JavaScript 中,函式就是一等公民。
函式作為一等公民
函式可以作為變數的值
在 JavaScript 中,函式可以被賦值給變數,這意味著你可以將函式當作變數使用,並隨時調用它。
範例:
const sayHello = function() {
console.log("Hello, world!");
};
sayHello(); // 輸出:Hello, world!
在這裡,我們定義了一個匿名函式並將它賦值給變數 sayHello
,之後就可以通過 sayHello()
調用這個函式。
函式可以作為參數傳遞
函式作為一等公民的另一個重要特性,是它可以作為參數傳遞給其他函式,這在高階函式中尤為常見。
範例:
function executeFunction(fn) {
fn();
}
executeFunction(function() {
console.log("這是作為參數傳遞的函式!");
});
在這個例子中,executeFunction
接受一個函式作為參數,並在內部調用該函式。
這種特性使得我們能夠靈活地處理函式,並實現各種強大的功能,如回調函式(Callback Functions)和高階函式(Higher-Order Functions)。
函式可以作為返回值
函式還可以作為另一個函式的返回值,這是許多 JavaScript 高階函式實現的基礎。
範例:
function createGreeter(greeting) {
return function(name) {
console.log(greeting + ", " + name);
};
}
const greet = createGreeter("Hello");
greet("Alice"); // 輸出:Hello, Alice
greet("Bob"); // 輸出:Hello, Bob
在這個例子中,createGreeter
返回一個函式,這個返回的函式可以根據不同的引數執行相應的操作。
這就是函式作為返回值的應用。
函式可以存儲在資料結構中
函式也可以像其他數據一樣存儲在資料結構中,如陣列或物件,並在需要時調用。
範例:
const functions = [
function() { console.log("函式 1"); },
function() { console.log("函式 2"); },
];
functions[0](); // 輸出:函式 1
functions[1](); // 輸出:函式 2
在這裡,我們將兩個匿名函式存儲在一個陣列中,並可以透過索引來調用它們。
高階函式:一等公民的應用
由於函式是 JavaScript 中的一等公民,我們可以輕鬆地實現高階函式。
高階函式是接受一個或多個函式作為參數,或返回一個函式的函式。
例子:回調函式
回調函式是 JavaScript 中常見的模式,用於處理異步操作(如事件處理、網絡請求等)。回調函式就是傳遞給另一個函式的函式。
範例:
function fetchData(callback) {
setTimeout(() => {
callback("資料已加載");
}, 1000);
}
fetchData(function(data) {
console.log(data); // 輸出:資料已加載
});
在這個例子中,fetchData
接受一個回調函式作為參數,並在數據加載完成後調用該回調函式。
例子:陣列方法中的高階函式
許多陣列方法(如 map
、filter
和 reduce
)都是高階函式,因為它們接受函式作為參數來操作陣列中的每個元素。
範例:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function(num) {
return num * 2;
});
console.log(doubled); // 輸出:[2, 4, 6, 8, 10]
在這個例子中,我們將一個匿名函式傳遞給 map
,map
函式會對陣列中的每個元素應用這個函式,並返回一個新的陣列。
一等公民帶來的靈活性
由於函式是 JavaScript 中的一等公民,這賦予了語言極大的靈活性。
開發者可以利用這種特性來撰寫可重用的代碼,實現各種強大的功能,如函式式編程、閉包、事件驅動程式設計等。
函式式編程
JavaScript 的函式式編程風格依賴於函式作為一等公民,允許我們將函式作為數據進行傳遞和操作,這提高了代碼的可組合性和可重用性。
閉包的實現
閉包是 JavaScript 中一個強大的概念,它的實現依賴於函式作為一等公民。
閉包允許函式「記住」它們在創建時的上下文,並在未來的某個時刻訪問這些上下文變數。
範例:
function counter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const increment = counter();
increment(); // 輸出:1
increment(); // 輸出:2
這裡的 counter
函式返回了一個閉包,這個閉包能夠記住並訪問 counter
函式中的 count
變數,即使在 counter
函式已經執行完畢後。
函式不是唯一的一等公民
雖然本文的重點是函式作為 JavaScript 中的一等公民,但事實上,JavaScript 中的其他數據類型(如物件、陣列等)也是一等公民。
這意味著我們可以對它們進行相同的操作,如賦值、傳遞作為參數、作為函式返回值等。
結語
JavaScript 中的「一等公民」概念是理解這個語言強大功能的基礎,特別是函式作為一等公民賦予了 JavaScript 極大的靈活性和表現力。
透過理解函式可以像數據一樣操作,我們可以實現更高效、可重用的代碼,並且更容易實現函式式編程的各種模式。
希望這篇文章能夠幫助新手,掌握 JavaScript 中函式作為一等公民的概念,並在實際開發中靈活應用。