Skip to content

2026-06-15

/ 12 分鐘閱讀

/ Deep JavaScript Foundations v3

為什麼要命名函式表達式:三個不可迴避的理由

本文延續上一篇對函式宣告與函式表達式的討論。上一篇建立了兩者在範疇歸屬上的差異,這篇要回答一個更實踐性的問題:為什麼 Kyle Simpson 強烈建議永遠使用命名函式表達式,而非匿名函式表達式?

匿名函式表達式的問題

在 jQuery 盛行的年代到現在,匿名函式表達式幾乎無所不在:

javascript
// 匿名函式表達式(極為常見,但有問題)
arr.map(function(x) { return x * 2; });

promise.then(function() { doSomething(); });

這種寫法的唯一優點是打字省力。Kyle Simpson 主張,這不是一個足以成立的理由。

理由一:可靠的自我參考

命名函式表達式的名稱會成為函式自身範疇內的唯讀識別字,讓函式能從內部可靠地引用自己:

javascript
// 匿名版本:若需要自我參考,只能依賴外層變數(不可靠)
var doSomething = function() {
    doSomething();   // 依賴外層 doSomething,但它可被重新賦值
};

// 命名版本:名稱在自身範疇內,唯讀且可靠
var doSomething = function doSomething() {
    doSomething();   // 引用自身範疇的唯讀識別字
};

需要自我參考的場景包括:遞迴呼叫、事件監聽器解除綁定(需要引用自身來 removeEventListener)、存取函式物件的屬性(如 lengthname)。自身範疇的唯讀名稱,永遠比外層可被修改的變數更可靠。

理由二:可讀的錯誤堆疊追蹤

匿名函式在 stack trace 中只會顯示 anonymous,在大量使用的程式碼中根本無從辨識:

javascript
// 匿名函式的 stack trace(痛苦版)
at anonymous (app.min.js:1:32712)
at anonymous (app.min.js:1:18903)
at anonymous (app.min.js:1:5421)

// 命名函式的 stack trace(有意義版)
at handleUserClick (app.min.js:1:32712)
at processFormSubmit (app.min.js:1:18903)
at validateInputs (app.min.js:1:5421)

有語意的名稱讓你光看 stack trace 就能推斷 bug 的來源,甚至不需要打開原始碼。這在生產環境中尤其關鍵。

特別注意:將匿名函式賦值給變數有時可以推斷出名稱,但作為 callback 直接傳入時(如 .map.then),名稱推斷不會發生,只有明確命名才能確保名稱出現在 stack trace 中。

理由三:程式碼自我說明

javascript
// 讀者必須閱讀函式體才能理解它在做什麼
setTimeout(function() {
    // 幾行程式碼...
}, 1000);

// 名稱本身就是說明,不需要讀完內容
setTimeout(function handleSessionTimeout() {
    // 幾行程式碼...
}, 1000);

Kyle Simpson 的立場:每一個函式都有存在的目的,有目的就有名稱。如果你想不出一個好名稱,這通常是一個訊號,這個函式太複雜了,做了太多事,應該被拆解成更小的單元,直到每個單元的名稱變得顯而易見。

無法命名的函式是更深層問題的指標,而不是一個讓你寫匿名函式的藉口。

當你真的想不到名稱時

Kyle Simpson 分享他自己的工作習慣:先寫出函式,暫時用 TODO 作為名稱占位,在提交程式碼前搜尋所有 TODO 並補上正式名稱。這讓你在對函式有更清晰理解後,再做命名決定。

函式宣告 vs 函式表達式的選擇建議

情境建議
超過三行程式碼優先使用函式宣告
需要被多次呼叫使用函式宣告(即使只有一行)
一到三行的簡短邏輯可以使用命名函式表達式
任何情況下永遠加上名稱,不要寫匿名函式

小結

匿名函式表達式的唯一優點是少打幾個字,但代價是失去可靠的自我參考能力、損害 stack trace 的可讀性、以及迫使讀者閱讀函式體才能理解意圖。命名函式表達式解決了所有這三個問題。如果可以,更進一步使用函式宣告,名稱只需要寫一次,且不涉及變數賦值的複雜性。

複習

偏好命名函式表達式的三個主要理由是什麼?

  1. 創建對函式本身可靠的自我參考
  2. 提供更易於除錯的錯誤堆疊追蹤
  3. 透過清楚說明函式目的,讓程式碼更具自我說明性

命名函式如何改善 stack trace 的除錯體驗?

當函式有名稱時,它會以有意義的名稱出現在 stack trace 中,讓開發者更容易理解錯誤的來源和上下文,而不需要閱讀整段程式碼。

為什麼函式的名稱對程式碼可讀性很重要?

函式名稱說明了函式存在的原因,免除了讀者閱讀函式體才能推斷目的的需要,並立即傳達函式的意圖。

對於難以命名的函式,建議採取什麼方式?

如果一個函式難以命名,這可能意味著函式過於複雜,應該被拆解成更小、更聚焦的單元,直到每個單元的名稱變得清楚顯而易見。

什麼時候應該將函式表達式轉換為函式宣告?

一般而言,如果函式超過三行程式碼,或需要被多次呼叫,就應該轉換為函式宣告。

小測驗

偏好命名函式表達式的第一個關鍵理由是什麼? 從函式內部創建對自身可靠的自我參考
命名函式表達式如何改善除錯? 它們提供更易讀的 stack trace
使用命名函式表達式的第三個理由是什麼? 讓程式碼更具自我說明性
什麼情況下可能偏好函式表達式而非函式宣告? 當函式少於三行程式碼時

此文章是 FrontendMasters 上的 Deep JavaScript Foundations, v3 課程筆記

最後更新時間:

Buy Me A Coffee

系列章節 第 40 篇 / 共 51 篇

0 %
MIT Licensed | Copyright © 2025-present Wen-Hsiu's Blog
Photo by Federica Galli on Unsplash