[譯]在 JavaScript 中 為什麼你應當使用 map 和 filter 來替代 forEach

趙小生發表於2018-09-10

當你需要將一個陣列或一部分陣列複製到一個新陣列時,首選 mapfilter,而不是 forEach

諮詢工作對我來說最大的好處之一是我可以看到無數的專案。這些專案有大有小,使用的程式語言和開發人員能力差異很大。儘管我認為有很多模式都應該放棄使用,但 JavaScript 語言中的這種模式尤其要棄用:使用 forEach 建立新陣列。該模式實際上非常簡單,看起來像這樣:

const kids = [];
people.forEach(person => {
  if (person.age < 15) {
    kids.push({ id: person.id, name: person.name });
  }
});
複製程式碼

這段程式碼的意思是,處理一個包含所有人的陣列,以找出每個年齡小於 15 歲的人。然後選擇 person 物件中的其中幾個欄位作為 'kids' 物件,並將其複製到 kids 陣列中。

雖然這是有效的,但這是非常必要的(參見程式設計範例)編碼方式。你可能有所懷疑,這有什麼不對?要理解這一點,讓我們首先熟悉兩個朋友 mapfilter

mapfilter

在 2015 年,mapfilter 作為 ES6 特性集的一部分被引入 JavaScript。它們是陣列的方法,允許在 JavaScript 中進行更多函數語言程式設計。像在函數語言程式設計世界中一樣,這兩種方法都沒有改變原始陣列。相反,它們都返回一個新陣列。它們都接受函式型別的單個引數。然後在原始陣列中的每一項上呼叫此函式以生成結果陣列。讓我們看看這些方法的作用:

  • map:每項呼叫函式處理後的值存放到返回的新陣列中。
  • filter:每項呼叫函式處理後的值決定該項是否應該放在方法返回的新陣列中。

在同一個團體中他們也有第三個朋友,但較少使用。這位朋友的名字是 reduce

以下是可以檢視實際操作結果的簡單示例:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(number => number * 2); // [2, 4, 6, 8, 10]
const even = numbers.filter(number => number % 2 === 0); // [2, 4]
複製程式碼

既然我們知道 mapfilter 會做什麼,讓我們接下來看一個我希望前面的示例應當如何編寫的例子:

const kids = people
  .filter(person => person.age < 15)
  .map(person => ({ id: person.id, name: person.name }));
複製程式碼

如果您想知道 map 中使用的 lambda 的語法,請參閱此 Stack Overflow answer 以獲取解釋。

那麼這個實現究竟有什麼好處:

  • 關注點分離:過濾和更改資料格式是兩個獨立的問題,使用單獨的方法可以分離關注點。
  • 可測試性:為實現這兩個目的,一個簡單的、純函式的方法可以輕鬆地針對各種行為進行單元測試。值得注意的是,初始實現並不像它依賴於其範圍 (kids 陣列)之外的某些狀態那樣純粹。
  • 可讀性:由於這些方法具有過濾資料或更改資料格式的明確目的,因此很容易看出正在進行何種操作。特別是因為有那些同類功能的函式,如 reduce
  • 非同步程式設計:forEachasync/await 不能很好地協同工作。另一方面,map 提供了一個能夠結合 promises 和 async/await 的有效模式。在下一篇博文中有關於此問題的更多資訊。

另一個值得注意的地方是,當你想引起副作用時(例如更改全域性狀態),不應當使用 map。特別是在不使用或儲存 map 方法的返回值的情況下。

結論

mapfilter 的使用提供了許多好處,例如關注點分離、可測試性、可讀性和對非同步程式設計的支援。因此,對我來說這是一個明智的選擇。然而,我經常遇到使用 forEach 的開發人員。雖然函數語言程式設計可能令人害怕,這些方法有也具有來自該世界的某些特徵,對它們並不用害怕。在響應式程式設計中,mapfilter 也被大量使用,感謝 RxJS 的貢獻,響應式程式設計現在越來越多地在 JavaScript 世界中使用。因此,下次你要寫一個 forEach 時,首先要考慮其他方法。但要注意,它們可能會永久改變您的編碼方式。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章