2021 年 2 月 1 日

箭頭函數回顧

讓我們回顧一下箭頭函數。

箭頭函數不只是用來撰寫小東西的「速記」。它們有一些非常具體且有用的功能。

在 JavaScript 中,我們需要撰寫在其他地方執行的函數的情況很多。

例如

  • arr.forEach(func)funcforEach 對陣列中的每個項目執行。
  • setTimeout(func)func 由內建排程器執行。
  • …還有更多。

在 JavaScript 中,建立函數並將其傳遞到某個地方是其精神所在。

而在這些函數中,我們通常不希望離開目前的內容。這就是箭頭函數派上用場的地方。

箭頭函數沒有「this」

正如我們在章節 物件方法,「this」 中所記得的,箭頭函數沒有 this。如果存取了 this,它會從外部取得。

例如,我們可以使用它在物件方法中進行反覆運算

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(
      student => alert(this.title + ': ' + student)
    );
  }
};

group.showList();

forEach 中,使用箭頭函式,所以其中的 this.title 與外部方法 showList 中的完全相同。也就是:group.title

如果我們使用「一般」函式,就會發生錯誤

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(function(student) {
      // Error: Cannot read property 'title' of undefined
      alert(this.title + ': ' + student);
    });
  }
};

group.showList();

錯誤發生是因為 forEach 預設以 this=undefined 執行函式,所以會嘗試存取 undefined.title

這不會影響箭頭函式,因為它們根本沒有 this

箭頭函式無法使用 new 執行

沒有 this 自然意味著另一個限制:箭頭函式無法作為建構函式使用。它們無法使用 new 呼叫。

箭頭函式與 bind

箭頭函式 => 與使用 .bind(this) 呼叫的一般函式之間存在細微的差異

  • .bind(this) 會建立函式的「繫結版本」。
  • 箭頭 => 沒有建立任何繫結。函式根本沒有 thisthis 的查詢方式與一般變數搜尋完全相同:在外部詞彙環境中。

箭頭沒有「引數」

箭頭函式也沒有 arguments 變數。

這對於裝飾器來說非常棒,因為我們需要使用目前的 thisarguments 轉發呼叫。

例如,defer(f, ms) 會取得一個函式,並回傳一個包裝函式,延遲 ms 毫秒呼叫它

function defer(f, ms) {
  return function() {
    setTimeout(() => f.apply(this, arguments), ms);
  };
}

function sayHi(who) {
  alert('Hello, ' + who);
}

let sayHiDeferred = defer(sayHi, 2000);
sayHiDeferred("John"); // Hello, John after 2 seconds

沒有箭頭函式的寫法會像這樣

function defer(f, ms) {
  return function(...args) {
    let ctx = this;
    setTimeout(function() {
      return f.apply(ctx, args);
    }, ms);
  };
}

這裡我們必須建立額外的變數 argsctx,以便 setTimeout 內部的函式可以取得它們。

摘要

箭頭函式

  • 沒有 this
  • 沒有 arguments
  • 無法使用 new 呼叫
  • 它們也沒有 super,但我們還沒學到它。我們會在 類別繼承 章節中學習

這是因為它們是針對沒有自己「內容」的短程式碼而設計的,而是用於目前的內容。它們在這種使用案例中真的非常出色。

教學課程地圖

留言

留言前請先閱讀…
  • 如果你有改善建議,請 提交 GitHub 議題 或提交 pull request,而不是留言。
  • 如果你無法理解文章中的內容,請說明。
  • 要插入幾行程式碼,請使用 <code> 標籤,要插入多行,請將它們包在 <pre> 標籤中,要插入超過 10 行,請使用沙盒 (plnkrjsbincodepen…)