初學者指南:深入了解 JavaScript 中的「一等公民」概念

更新日期: 2025 年 1 月 23 日

在學習 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 接受一個回調函式作為參數,並在數據加載完成後調用該回調函式。

例子:陣列方法中的高階函式

許多陣列方法(如 mapfilterreduce)都是高階函式,因為它們接受函式作為參數來操作陣列中的每個元素。

範例:

const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map(function(num) {
  return num * 2;
});

console.log(doubled); // 輸出:[2, 4, 6, 8, 10]

在這個例子中,我們將一個匿名函式傳遞給 mapmap 函式會對陣列中的每個元素應用這個函式,並返回一個新的陣列。


一等公民帶來的靈活性

由於函式是 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 中函式作為一等公民的概念,並在實際開發中靈活應用。


參考資料

Similar Posts