來源: https://medium.com/better-programming,做者:Moon,翻譯:公衆號《前端全棧開發者》
JavaScript中一些最受歡迎的功能多是map和forEach。從ECMAScript 5(簡稱es5)開始,它們就開始存在了。javascript
在本文中,我將討論它們之間的主要區別,並向你展現其用法的一些示例。前端
基本上,在JavaScript中遍歷對象取決於對象是否可迭代。默認狀況下,數組是可迭代的。map
和 forEach
包含在Array.prototype
中,所以咱們無需考慮可迭代性。若是你想進一步學習,我推薦你看看什麼是JavaScript中的可迭代對象!java
map
和 forEach
是數組中的幫助器方法,能夠輕鬆地在數組上循環。咱們曾經像下面這樣循環遍歷一個數組,沒有任何輔助函數。數組
var array = ['1', '2', '3']; for (var i = 0; i < array.length; i += 1) { console.log(Number(array[i])); } // 1 // 2 // 3
自JavaScript時代開始以來,就一直存在 for
循環。它包含3個表達式:初始值,條件和最終表達式。函數
這是循環數組的經典方法。從ECMAScript 5開始,新功能彷佛使咱們更加快樂。學習
map
的做用與 for
循環徹底相同,只是 map
會建立一個新數組,其結果是在調用數組中的每一個元素上調用提供的函數。測試
它須要兩個參數:一個是稍後在調用 map
或 forEach
時調用的回調函數,另外一個是回調函數被調用時使用的名爲 thisArg
的上下文變量。this
const arr = ['1', '2', '3']; // 回調函數接受3個參數 // 數組的當前值做爲第一個參數 // 當前值在數組中的位置做爲第二個參數 // 原始源數組做爲第三個參數 const cb = (str, i, origin) => { console.log(`${i}: ${Number(str)} / ${origin}`); }; arr.map(cb); // 0: 1 / 1,2,3 // 1: 2 / 1,2,3 // 2: 3 / 1,2,3
回調函數能夠以下使用。es5
arr.map((str) => { console.log(Number(str)); })
map
的結果不等於原始數組。spa
const arr = [1]; const new_arr = arr.map(d => d); arr === new_arr; // false
你還能夠將對象做爲 thisArg
傳遞到map。
const obj = { name: 'Jane' }; [1].map(function() { // { name: 'Jane' } console.dir(this); }, obj); [1].map(() => { // window console.dir(this); }, obj);
對象 obj
成爲 map
的 thisArg
。可是箭頭回調函數沒法將 obj
做爲其 thisArg
。
這是由於箭頭函數與正常函數不一樣。
forEach
是數組的另外一個循環函數,但 map
和 forEach
在使用中有所不一樣。map
和 forEach
可使用兩個參數——回調函數和 thisArg
,它們用做其 this
。
const arr = ['1', '2', '3']; // 回調函數接受3個參數 // 數組的當前值做爲第一個參數 // 當前值在數組中的位置做爲第二個參數 // 原始源數組做爲第三個參數 const cb = (str, i, origin) => { console.log(`${i}: ${Number(str)} / ${origin}`); }; arr.forEach(cb); // 0: 1 / 1,2,3 // 1: 2 / 1,2,3 // 2: 3 / 1,2,3
那有什麼不一樣?
map
返回其原始數組的新數組,可是 forEach
卻沒有。可是它們都確保了原始對象的不變性。
[1,2,3].map(d => d + 1); // [2, 3, 4]; [1,2,3].forEach(d => d + 1); // undefined;
若是更改數組內的值,forEach
不能確保數組的不變性。這個方法只有在你不接觸裏面的任何值時,才能保證不變性。
[{a: 1, b: 2}, {a: 10, b: 20}].forEach((obj) => obj.a += 1); // [{a: 2, b: 2}, {a: 11, b: 21}] // 數組已更改!
因爲它們之間的主要區別在因而否有返回值,因此你會但願使用 map
來製做一個新的數組,而使用 forEach
只是爲了映射到數組上。
這是一個簡單的例子。
const people = [ { name: 'Josh', whatCanDo: 'painting' }, { name: 'Lay', whatCanDo: 'security' }, { name: 'Ralph', whatCanDo: 'cleaning' } ]; function makeWorkers(people) { return people.map((person) => { const { name, whatCanDo } = person; return <li key={name}>My name is {name}, I can do {whatCanDo}</li> }); } <ul>makeWorkers(people)</ul>
好比在React中,map
是很是經常使用的製做元素的方法,由於 map
在對原數組的數據進行操做後,會建立並返回一個新的數組。
const mySubjectId = ['154', '773', '245']; function countSubjects(subjects) { let cnt = 0; subjects.forEach(subject => { if (mySubjectId.includes(subject.id)) { cnt += 1; } }); return cnt; } countSubjects([ { id: '223', teacher: 'Mark' }, { id: '154', teacher: 'Linda' } ]); // 1
另外一方面,當你想對數據進行某些操做而不建立新數組時,forEach
頗有用。順便說一句,可使用 filter
重構示例。
subjects.filter(subject => mySubjectId.includes(subject.id)).length;
綜上所述,我建議你在建立一個新的數組時使用map,當你不須要製做一個新的數組,而是要對數據作一些事情時,就使用forEach。
有些帖子提到 map
比 forEach
快。因此,我很好奇這是否是真的。我找到了這個對比結果。
該代碼看起來很是類似,但結果卻相反。有些測試說 forEach
更快,有些說 map
更快。也許你在告訴本身 map/forEach
比其餘的快,你多是對的。老實說,我不肯定。我認爲在現代Web開發中,可讀性比 map
和 forEach
之間的速度重要得多。
但能夠確定的是——二者都比JavaScript內置的 for
循環慢。