返回文章列表

一般函式 vs. 箭頭函式:差異與使用時機

12 分鐘
前端JavaScript

一般函式 vs. 箭頭函式:差異與使用時機

JavaScript 有兩種主要的函式寫法:一般函式 (Function) 與箭頭函式 (Arrow Function)。

兩者在語法上不同,但更關鍵的是:它們在行為上也有差異,尤其是 this 的運作方式。


語法差異

一般函式:

JavaScript
function plus(a, b) {
  return a + b;
}

箭頭函式:

JavaScript
const plus = (a, b) => a + b;

箭頭函式的語法更精簡,支援隱式回傳,適合用來寫簡短的邏輯。


this 的差異

這是兩者最重要的差異。

一般函式

一般函式的 this 是動態的,取決於「誰呼叫了這個函式」。

JavaScript
const obj = {
  value: 10,
  show: function () {
    console.log(this.value); // 10
  }
};

obj.show();

this 指向 obj,因為是 obj 呼叫了 show

箭頭函式

箭頭函式沒有自己的 this,它的 this 來自外層作用域 (lexical this)。

JavaScript
const obj = {
  value: 10,
  show: () => {
    console.log(this.value); // undefined
  }
};

obj.show();

this 不會指向 obj,而是指向外層的作用域。

實際案例:setTimeout

this 的差異在非同步情境中特別明顯。

一般函式:

JavaScript
const timer = {
  seconds: 0,
  start: function () {
    setTimeout(function () {
      this.seconds++; // this 不是 timer
      console.log(this.seconds); // NaN
    }, 1000);
  }
};

箭頭函式:

JavaScript
const timer = {
  seconds: 0,
  start: function () {
    setTimeout(() => {
      this.seconds++; // this 是 timer
      console.log(this.seconds); // 1
    }, 1000);
  }
};

箭頭函式繼承了外層 startthis,所以可以正確存取 timer.seconds


arguments 的差異

一般函式有內建的 arguments 物件,可以存取所有傳入的參數:

JavaScript
function test() {
  console.log(arguments); // [1, 2, 3]
}

test(1, 2, 3);

箭頭函式沒有自己的 arguments

JavaScript
const test = () => {
  console.log(arguments); // ReferenceError 或外層的 arguments
};

如果需要處理不固定數量的參數,箭頭函式應該改用 Rest Parameter:

JavaScript
const test = (...args) => {
  console.log(args); // [1, 2, 3]
};

建構函式

一般函式可以作為建構函式使用:

JavaScript
function Person(name) {
  this.name = name;
}

const p = new Person("Charmy");
console.log(p.name); // "Charmy"

箭頭函式不能作為建構函式,因為它沒有 prototype,也不支援 new

JavaScript
const Person = (name) => {
  this.name = name;
};

new Person("Charmy"); // TypeError

Hoisting

一般函式宣告會被提升,可以在宣告之前呼叫:

JavaScript
greet(); // "Hello"

function greet() {
  console.log("Hello");
}

箭頭函式是函式表達式,不會被提升:

JavaScript
greet(); // ReferenceError

const greet = () => {
  console.log("Hello");
};

差異總覽

一般函式箭頭函式
語法較冗長簡潔
this動態,取決於呼叫者繼承外層作用域
arguments無 (用 rest parameter 代替)
建構函式可以不行
Hoisting會提升不會提升

使用時機

建議使用箭頭函式

陣列方法,邏輯簡短時:

JavaScript
const doubled = [1, 2, 3].map(n => n * 2);
const evens = [1, 2, 3, 4].filter(n => n % 2 === 0);

Promise 鏈:

JavaScript
fetch(url)
  .then(response => response.json())
  .then(data => console.log(data));

需要保留外層 this 的回呼函式:

JavaScript
setTimeout(() => {
  this.update();
}, 1000);

建議使用一般函式

物件方法,需要存取 this

JavaScript
const user = {
  name: "Charmy",
  greet() {
    console.log(this.name); // "Charmy"
  }
};

建構函式:

JavaScript
function Person(name) {
  this.name = name;
}

需要 Hoisting 的情況,例如把函式宣告放在檔案底部:

JavaScript
init();

function init() {
  // 可以正常執行
}

總結

一般函式與箭頭函式各有適合的使用場景。

需要動態 this 就用一般函式,需要繼承外層 this 就用箭頭函式。

語法簡潔是箭頭函式的優點,但不是選擇它的唯一理由。

理解兩者的差異,才能在正確的情境選對工具。