JavaScript中的map()和forEach()有什麼區別?

banner.jpeg

來源: https://medium.com/better-programming,做者:Moon,翻譯:公衆號《前端全棧開發者》

JavaScript中一些最受歡迎的功能多是map和forEach。從ECMAScript 5(簡稱es5)開始,它們就開始存在了。javascript

在本文中,我將討論它們之間的主要區別,並向你展現其用法的一些示例。前端

閱讀以前

基本上,在JavaScript中遍歷對象取決於對象是否可迭代。默認狀況下,數組是可迭代的。mapforEach 包含在Array.prototype 中,所以咱們無需考慮可迭代性。若是你想進一步學習,我推薦你看看什麼是JavaScript中的可迭代對象!java

什麼是map()和forEach()?

mapforEach 是數組中的幫助器方法,能夠輕鬆地在數組上循環。咱們曾經像下面這樣循環遍歷一個數組,沒有任何輔助函數。數組

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

map 的做用與 for 循環徹底相同,只是 map 會建立一個新數組,其結果是在調用數組中的每一個元素上調用提供的函數。測試

它須要兩個參數:一個是稍後在調用 mapforEach 時調用的回調函數,另外一個是回調函數被調用時使用的名爲 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 成爲 mapthisArg。可是箭頭回調函數沒法將 obj 做爲其 thisArg

這是由於箭頭函數與正常函數不一樣。

forEach

forEach 是數組的另外一個循環函數,但 mapforEach 在使用中有所不一樣。mapforEach 可使用兩個參數——回調函數和 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()?

因爲它們之間的主要區別在因而否有返回值,因此你會但願使用 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。

速度比較

有些帖子提到 mapforEach 快。因此,我很好奇這是否是真的。我找到了這個對比結果。

1.png
2.png

該代碼看起來很是類似,但結果卻相反。有些測試說 forEach 更快,有些說 map 更快。也許你在告訴本身 map/forEach 比其餘的快,你多是對的。老實說,我不肯定。我認爲在現代Web開發中,可讀性比 mapforEach 之間的速度重要得多。

但能夠確定的是——二者都比JavaScript內置的 for 循環慢。

subscribe2.png

相關文章
相關標籤/搜索