什麼是箭頭函式 (Arrow Function)?跟一般的函式有什麼差別?

2022年10月27日

💎 加入 E+ 成長計畫 與超過 300+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

箭頭函式是在 ES6 後出現的一種函式表現方式,雖然也是函式的一種,但有部分的特性是跟一般函式有差異的,在面試中屬於高頻題,需要特別注意。

箭頭函式和一般函式差異

箭頭函式和一般函式的主要差異有四點,我們將在下方詳細說明:

  1. 箭頭函式語法不同、寫法也較簡潔
  2. 箭頭函式沒有自己的 this、也無法直接修改 this 的指向
  3. 箭頭函式沒有自己的 arguments
  4. 箭頭函式不能作為構造函式使用

語法更為簡潔

箭頭函式相比於一般函式,語法相當簡潔。除了少去 function 關鍵字,如果只有一個參數,箭頭函式可以省略括號;只有一行程式碼,就是直接簡單返回一個變數或簡單的表達式,可以省略大括號和 return。例子如下:

// ES5 一般函式
let addOne = function (n) {
  return n + 1;
};
// ES6 箭頭函式,參數只有一個時,參數的括號可以省略
let addOne = (n) => {
  return n + 1;
};
// ES6 箭頭函式,只有一行時,省略大括號和 return
let addOne = (n) => n + 1;

this 值與一般函式不同

箭頭函式沒有自己的 this 值,箭頭函式的 this 值是在一開始定義時就決定,永遠會是最接近自己的外層的普通函式中的 this 值。此外,箭頭函式也不適合使用 call、 applybind 來綁定 this 值,綁定值會無效。一般函式的 this 值,則是基於函式如何被調用來決定,詳細可參考《請解釋 JavaScript 中 this 的值》一文。

一般函式中 this 可以被綁定,以下為程式碼綁定範例

const obj = {
  num: 100,
};

window.num = 2020;

const add = function (a, b, c) {
  return this.num + a + b + c;
};

// 綁定 this 值為 obj,obj 的 num 為 100,所以 resultCall 是 106
const resultCall = add.call(obj, 1, 2, 3);
console.log(resultCall); // 106

箭頭函式中 this 綁定會無效,以下為程式碼綁定範例

const obj = {
  num: 100,
};

window.num = 2020;

const add = (a, b, c) => this.num + a + b + c;

// 綁定 this 無效,add 函式的 this 會是 window
// 所以 num 會是 2020,resultCall 則是 2026
console.log(add.call(obj, 1, 2, 3)); // 2026

利用箭頭函式沒有自己的 this 值的特性,很適合用在 setTimeout()EventTarget.prototype.addEventListener() 等方法當中,因為它可以自動綁定在適合的範圍中。可以看到下方 setTimeout 當中,用一般函式與用箭頭函式的 this 區別:

// 一般函式版本,this 值在這狀況是 NaN
const obj = {
  count: 10,
  doSomethingLater() {
    setTimeout(function () {
      // 此 function 為一般函式,因此 this 指向 window
      this.count++;
      console.log(this.count); // NaN (因為在 windonw 中沒有 count)
    }, 300);
  },
};
obj.doSomethingLater();

// 箭頭函式版本
const obj = {
  count: 10,
  doSomethingLater() {
    // 此 function 為箭頭函式,因此 this 會依據最接近的父層一般函式的 this 值,這里為 obj
    setTimeout(() => {
      this.count++;
      console.log(this.count); // 11 (obj 的 count 原本是 10,10++ 會是 11)
    }, 300);
  },
};
obj.doSomethingLater();

沒有自己的 arguments

不像一般函式,箭頭函式沒有 arguments 物件,但好處是,箭頭函式可以獲取最近的非箭頭函式的 arguments 物件,如下範例

箭頭函式中 arguments 程式碼範例

// 箭頭函式沒有自己的 arguments,因此會往父層尋找
// 這邊的父層是全域環境,因此找到全域環境中的 arguments 變數
// 在全域環境 arguments[0] 為 1
const arguments = [1, 2, 3];
const arr = () => arguments[0];
arr(); // 1

// 一般函式有 arguments 物件,就是傳入的參數,在這邊的 arguments 是 [3]
// 所以 arguments[0] 也會是 3
// f() 則會是 3 + 3
function foo(n) {
  const f = () => arguments[0] + n;
  return f();
}
foo(3); // 3 + 3 = 6

如果需要使用到箭頭函式的所有參數,可以用以下剩餘參數(rest parameter) 的寫法得到

let nums = (...nums) => {
  console.log(nums);
};
nums(1, 2, 3, 4, 5); //[1,2,3,4,5]

不能作為構造函式使用

箭頭函式不能作為構造函式使用,換言之不能用 new 關鍵字調用,會報錯

const arrowFun = () => {};
new arrowFun(); // error: arrowFun is not a constructor

總結

  1. 箭頭函式語法不同、寫法也較簡潔
  2. 箭頭函式沒有自己的 this、也無法直接修改 this 的指向
  3. 箭頭函式沒有自己的 arguments
  4. 箭頭函式不能作為構造函式使用
🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們