本文 AI 產出,尚未審核

JavaScript ES6+ 新特性:箭頭函式 (Arrow Function)


簡介

在 ES6 以前,我們撰寫函式大多使用 function 關鍵字。雖然功能完整,但在語法上往往較為冗長,且 this 綁定 的行為容易讓新手感到困惑。
ES6 引入的 箭頭函式(Arrow Function)以更簡潔的語法取代傳統函式,讓程式碼更易讀、寫起來更流暢,同時也改變了 thisargumentssupernew.target 的繫結方式,成為現代 JavaScript(Modern JS)開發的常用工具。

掌握箭頭函式不僅能提升開發效率,還能避免許多因 this 指向錯誤而產生的 bug,對於從前端框架(如 React、Vue)到 Node.js 後端服務,都是必備的基礎知識。


核心概念

1. 基本語法

傳統函式:

function add(a, b) {
  return a + b;
}

等價的箭頭函式:

const add = (a, b) => a + b;
  • 參數:若只有一個參數,圓括號可省略;若沒有參數,必須寫 () =>
  • 函式主體:若只有單一表達式且直接回傳,省略大括號與 return;若需要多行程式碼或執行副作用,則需加上大括號與 return(若有回傳值)。
// 無參數
const getTime = () => Date.now();

// 單一參數
const double = n => n * 2;

// 多行程式碼
const filterEven = arr => {
  const result = [];
  for (const n of arr) {
    if (n % 2 === 0) result.push(n);
  }
  return result;
};

2. this 的行為

傳統函式 在被呼叫時會自行決定 this 的指向(依照呼叫方式或 call/apply/bind)。
箭頭函式 則不會產生自己的 this,它會 「捕獲」(lexical capture)外層執行環境的 this,相當於把外層的 this「閉包」進來。

const obj = {
  value: 42,
  // 傳統函式:this 依照呼叫方式決定
  getValue() {
    setTimeout(function () {
      console.log('傳統函式 this.value =', this.value);
    }, 100);
  },
  // 箭頭函式:this 直接繼承自 obj
  getValueArrow() {
    setTimeout(() => {
      console.log('箭頭函式 this.value =', this.value);
    }, 100);
  }
};

obj.getValue();        // undefined(因為 this 指向全域或 undefined)
obj.getValueArrow();   // 42

重點:在需要保留外層 this(例如在回呼、setTimeoutPromise 中)時,箭頭函式是最直觀的解決方案

3. argumentssupernew.target

  • arguments:箭頭函式不擁有自己的 arguments 物件,若需要存取傳入參數,可直接使用命名參數或展開運算子(...args)。
  • super:在類別的子類別建構子或方法中,箭頭函式會繼承外層的 super 參照。
  • new.target:同樣不會被箭頭函式擁有,若需要檢查是否使用 new 呼叫,仍須使用傳統函式或類別語法。
function traditional(...args) {
  console.log(arguments); // 有 arguments 物件
}
const arrow = (...args) => {
  // console.log(arguments); // ReferenceError
  console.log(args);        // 使用展開運算子取得參數
};
traditional(1, 2, 3);
arrow(1, 2, 3);

4. 何時不能使用箭頭函式

情境 為什麼不能使用 替代方案
需要 new 建立實例 箭頭函式沒有 [[Construct]] 內部方法 使用傳統函式或 class
需要 this 隨呼叫者改變(如事件處理器需要 element) this 被 lexical 綁定 使用傳統函式或 event.currentTarget
必須使用 arguments 物件 arguments 使用 ...args 或傳統函式

程式碼範例

範例 1:陣列操作的簡潔寫法

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

// map + arrow
const squares = numbers.map(n => n ** 2);
console.log(squares); // [1, 4, 9, 16, 25]

// filter + arrow (保留偶數)
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]

說明:使用箭頭函式讓 mapfilter 等高階函式的回呼變得一目了然,避免冗長的 function 關鍵字。

範例 2:在 Promise 中保留 this

class ApiService {
  constructor(baseURL) {
    this.baseURL = baseURL;
  }

  fetchUser(id) {
    // this 必須指向 ApiService 實例
    return fetch(`${this.baseURL}/users/${id}`)
      .then(res => res.json())
      .then(user => {
        // 使用箭頭函式,this 仍指向 ApiService
        console.log('取得使用者', this.baseURL, user);
        return user;
      });
  }
}

const api = new ApiService('https://jsonplaceholder.typicode.com');
api.fetchUser(1);

關鍵then 內的箭頭函式自動捕獲 ApiServicethis,不必額外 bind(this)

範例 3:事件處理器的 this 差異

<button id="btn1">傳統函式</button>
<button id="btn2">箭頭函式</button>

<script>
document.getElementById('btn1').addEventListener('click', function () {
  // this 代表被點擊的 button
  console.log('傳統函式 this.id =', this.id);
});

document.getElementById('btn2').addEventListener('click', () => {
  // this 來自外層 (window),不是 button
  console.log('箭頭函式 this.id =', this.id);
});
</script>

實務提醒:在 DOM 事件處理時,若需要存取觸發元素,不要使用箭頭函式,除非你改用 event.currentTarget

範例 4:使用 ...args 取代 arguments

function sumTraditional() {
  // 使用 arguments
  let total = 0;
  for (let i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

const sumArrow = (...args) => args.reduce((a, b) => a + b, 0);

console.log(sumTraditional(1, 2, 3, 4)); // 10
console.log(sumArrow(1, 2, 3, 4));       // 10

說明:展開運算子讓參數取得更直觀,也避免了 arguments 造成的可讀性問題。

範例 5:在類別的 getter 中使用箭頭函式

class Counter {
  #count = 0;

  // getter 使用箭頭函式,保持 this 正確
  get value() {
    return (() => this.#count)();
  }

  increment() {
    this.#count++;
  }
}

const c = new Counter();
c.increment();
c.increment();
console.log(c.value); // 2

技巧:即使在 getter、setter 等特殊屬性裡,也可以利用箭頭函式確保 this 的正確指向。


常見陷阱與最佳實踐

陷阱 可能的錯誤 解決方式
誤用於事件處理 this 不指向目標元素,導致 undefined 或錯誤 使用傳統函式,或改用 event.currentTarget
忘記括號 單一參數時省略括號,若參數是解構或預設值就會語法錯誤 參數有解構、預設值或型別註記時,必須加括號
返回物件時忘記括號 => { a: 1 } 被解析為程式碼區塊,而非物件字面值 使用圓括號包住物件:=> ({ a: 1 })
使用 new 會拋出 TypeError: ... is not a constructor 改用傳統函式或 class
過度濫用 把所有函式都寫成箭頭,失去可讀性或語意 僅在需要 lexical this、簡短回呼時使用;較複雜的邏輯仍建議使用傳統函式或 class 方法

最佳實踐

  1. 保持簡潔:單行回傳時使用隱式返回,讓意圖一目了然。
  2. 明確 this:在需要 this 隨呼叫者改變的情境,堅持使用傳統函式。
  3. 使用 ...args:取代 arguments,提升可讀性與型別推斷。
  4. 避免返回物件時遺漏圓括號const fn = () => ({ foo: 'bar' });
  5. 遵循團隊 lint 規範:如 eslintprefer-arrow-callbackarrow-body-style 等規則,確保程式碼風格一致。

實際應用場景

  1. React 函式組件

    • 事件處理、useEffect 回呼、map 渲染列表等,都大量使用箭頭函式,讓 this 不必再手動綁定。
  2. Node.js 中的非同步流程

    • Promiseasync/await.then.catch.finally 中使用箭頭函式,可確保上下文一致,減少 bind 的使用。
  3. 高階函式庫(如 Lodash、Ramda)

    • 這類函式庫鼓勵以「函式式編程」的方式撰寫程式碼,箭頭函式的簡潔語法與不可變性概念相輔相成。
  4. Vue 3 Composition API

    • setup 函式內部的回呼(例如 watchcomputed)常以箭頭函式寫法呈現,讓組件狀態更易追蹤。
  5. 測試框架(Jest、Mocha)

    • 在測試案例的 ittest 回呼中使用箭頭函式,可避免 this 被測試框架意外改寫,減少測試錯誤。

總結

箭頭函式是 ES6+ 中最具代表性的語法糖之一,以更簡潔的寫法提供了 lexical thisarguments 的替代方案,讓開發者在處理回呼、非同步流程、陣列操作時能寫出更乾淨、可讀的程式碼。

  • 何時使用:簡短回呼、需要保留外層 this、不需要 new、不需要 arguments
  • 何時避免:需要動態 this、必須使用 new、需要 argumentsnew.target

掌握上述概念與最佳實踐,您就能在 前端框架、Node.js 伺服器、函式式程式設計 等各種情境下,安全且高效地運用箭頭函式,提升程式碼品質與開發效率。

祝您在 JavaScript 的旅程中寫出 更簡潔、更可靠 的程式!