js中forEach & map


背景

JavaScript中,數組的遍歷我們肯定都不陌生,最常見的兩個便是forEach 和 map。

(當然還有別的譬如for, for in, for of, reduce, filter, every, some, ...)

之所以幾天要寫這個, 是因為前幾天寫代碼的時候犯了一個低級且愚蠢的錯誤, 最后搞出了個小bug。

最后找到原因, 生氣, 甚至還有點想笑, 今天就寫一下這兩個方法。

 

正文

我撲街的代碼是這樣的, 要給一個數組中的對象加一個屬性, 我隨手就寫了如下代碼:

// Add input_quantity into every list item const dataSoruceAdapter = data => data.forEach((item) => { item.input_quantity = item.quantity }) // ... const transformedDataSource = dataSoruceAdapter(defaultDataSource); const [orderList, setOrderList] = useState(transformedDataSource);

后面發現, 數組是空的... 囧

感覺自己真蠢, 改一下:

const dataSoruceAdapter = data => data.map((item) => { item.input_quantity = item.quantity return item }) 

搞定。

我們仔細看一下forEach 和 map 這兩個方法:

 

對比和結論

forEach: 針對每一個元素執行提供的函數。

map: 創建一個新的數組,其中每一個元素由調用數組中的每一個元素執行提供的函數得來。

直接說結論吧:

forEach方法不會返回執行結果,而是undefined。

也就是說,forEach會修改原來的數組,而map方法會得到一個新的數組並返回。

下面我們看下具體的例子。

 

forEach

forEach 方法按升序為數組中含有效值的每一項執行一次callback 函數,那些已刪除或者未初始化的項將被跳過(例如在稀疏數組上)。

forEach 接收兩個參數: arr.forEach(callback[, thisArg]);

callback 函數會被依次傳入三個參數:

  1. 數組當前項的值
  2. 數組當前項的索引
  3. 數組對象本身

比如:

const arr = ['1', '2', '3']; // callback function takes 3 parameters // the current value of an array as the first parameter // the position of the current value in an array as the second parameter // the original source array as the third parameter 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 

如果 thisArg 參數有值,則每次 callback 函數被調用的時候,this 都會指向 thisArg 參數上的這個對象。

如果省略了 thisArg 參數, 或者賦值為 null 或 undefined,則 this 指向全局對象。

舉個勉強的例子,從每個數組中的元素值中更新一個對象的屬性:

function Counter() { this.sum = 0; this.count = 0; } Counter.prototype.add = function(array) { array.forEach(function(entry) { this.sum += entry; this.count++; }, this); // console.log(this) -> Counter }; var obj = new Counter(); obj.add([1, 3, 5, 7]); obj.count; // 4 obj.sum; // 16 

如果使用箭頭函數來傳入函數參數,thisArg 參數會被忽略,因為箭頭函數在詞法上綁定了 this 值。

一般情況下, 我們只會用到callback的前兩個參數。

 

map

map 做的事情和 for循環 一樣,不同的是, map 會創建一個新數組。

所以, 如果你不打算使用返回的新數組, 卻依舊使用map的話, 這是違背map的設計初衷的。

map 函數接收兩個參數:

  1. callback
    callback 也有三個參數:

    1. currentValue
    2. index
    3. array
  2. thisArg(可選)

這一點和forEach 是類似的。

具體的例子:


const arr = ['1', '2', '3']; // callback function takes 3 parameters // the current value of an array as the first parameter // the position of the current value in an array as the second parameter // the original source array as the third parameter 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 

callback 方法用例:

arr.map((str) => { console.log(Number(str)); })

map 之后的結果是一個新數組, 和原數組是不相等的:

const arr = [1]; const new_arr = arr.map(d => d); arr === new_arr; // false

你也可以指定第二個參數thisArg的值:

const obj = { name: 'Jane' }; [1].map(function() { console.dir(this); // { name: 'Jane' } }, obj); 

但是如果你使用的是箭頭函數, 此時的 this將會是 window:

[1].map(() => { console.dir(this); // window }, obj);

箭頭函數和普通函數的工作機制是不同的,不是本范圍,你可以看這篇文章了解具體細節:https://www.geeksforgeeks.org...

寫到這里, 就想起來一個經典的題目。

 

一個使用技巧案例

["1", "2", "3"].map(parseInt);

這道題我們都見過, 我們期望輸出 [1, 2, 3], 而實際結果是 [1, NaN, NaN]。

我們簡單來分析下過程, 首先看一下參數傳遞情況:

// parseInt(string, radix) -> map(parseInt(value, index))
第一次迭代(index is 0): parseInt("1", 0); // 1 第二次迭代(index is 1): parseInt("2", 1); // NaN 第三次迭代(index is 2): parseInt("3", 2); //NaN

看到這, 解決辦法也就呼之欲出了:

function returnInt(element) { return parseInt(element, 10); } ['1', '2', '3'].map(returnInt); // [1, 2, 3]

是不是很容易理解?

回到正題。

資源搜索網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com

forEach 和 map 的區別

看兩行代碼你就懂了:

[1,2,3].map(d => d + 1); // [2, 3, 4]; [1,2,3].forEach(d => d + 1); // undefined;

vue作者,尤雨溪大佬,有這么一個形象的比方:

foreach 就是你按順序一個一個跟他們做點什么,具體做什么,隨便:

people.forEach(function (dude) { dude.pickUpSoap(); });

map 就是你手里拿一個盒子(一個新的數組),一個一個叫他們把錢包扔進去。結束的時候你獲得了一個新的數組,里面是大家的錢包,錢包的順序和人的順序一一對應。

var wallets = people.map(function (dude) { return dude.wallet; });

reduce 就是你拿着錢包,一個一個數過去看里面有多少錢啊?每檢查一個,你就和前面的總和加一起來。這樣結束的時候你就知道大家總共有多少錢了。

var totalMoney = wallets.reduce(function (countedMoney, wallet) { return countedMoney + wallet.money; }, 0);

十分的貼切。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM