應該用forEach改變數組的值嗎? 原生JS forEach()和map()遍歷的異同點


應該用forEach改變數組的值嗎? https://segmentfault.com/q/1010000013170900?utm_source=index-hottest

 

由於js中的數組是引用類型,所以可以利用類似指針的特性通過改變另一個變量去修改原始的值。我認為這其實是js中的缺陷,所以我不喜歡利用這個"缺陷"去實現一些功能,在最近的一次code review中,同事指出了這個問題。所以我希望有更多朋友能給我一些建議。

下面就是簡單的例子。

let arr = [{ a:1, b:2, }, { a:3, b:4, }];

如果有以上數組,我需要將每一項的a改為3。大概有兩種寫法,一種是用forEach,另一種是用map來返回一個新數組(暫不考慮for循環)。

forEach:

arr.forEach((item) => { item.a = 3; });

map:

arr = arr.map((item) => { // 有同事指出應該聲明一個新變量來存儲map的結果,這個建議我認為是對的。 item.a = 3; return item; });
2018-02-06 提問
2 個回答
5

已采納

補充下,剛才沒仔細看題目。題目的map方法不夠“純粹”,實際上還是直接修改了每個item的屬性,要想不影響原有對象,應該這么寫:

arr = arr.map((item) => { // 有同事指出應該聲明一個新變量來存儲map的結果,這個建議我認為是對的。 return { ...item, a:3 } });

==============

map方法體現的是數據不可變的思想。該思想認為所有的數據都是不能改變的,只能通過生成新的數據來達到修改的目的,因此直接對數組元素對象屬性進行操作的行為都是不可取的。這種思想其實有很多好處,最直接的就是避免了數據的隱式修改。immutable.js是實現數據不可變的一個庫,可通過專屬的API對引用類型進行操作,每次形成一個新的對象。

但具體到項目中還是要看團隊的要求,都用或者都不用。單單局部使用是沒有效果的。

如果使用了React + Redux 的技術棧,是比較推薦使用的

另外有一點,forEachmap還存在一個編程思想的區別,前者是命令式編程,后者是聲明式編程,如果項目的風格是聲明式的,比如React,那么后者顯然更統一。

3

網絡上找了一點兒關於這個的一些比較和介紹,希望對你有所幫助!

原生JS forEach()和map()遍歷的異同點

共同點:

1、都是循環遍歷數組中的每一項。 2、forEach()和map()里面每一次執行匿名函數都支持3個參數:數組中的當前項item,當前項的索引index,原始數組input。 3、匿名函數中的this都是指Window。 4、只能遍歷數組。 

1.forEach()

沒有返回值

arr[].forEach(function(value,index,array){   //do something })

參數:value數組中的當前項, index當前項的索引, array原始數組;
數組中有幾項,那么傳遞進去的匿名回調函數就需要執行幾次;
理論上這個方法是沒有返回值的,僅僅是遍歷數組中的每一項,不對原來數組進行修改;但是可以自己通過數組的索引來修改原來的數組;

var ary = [12,23,24,42,1]; var res = ary.forEach(function (item,index,input) { input[index] = item*10; }) console.log(res);//--> undefined; console.log(ary);//--> 通過數組索引改變了原數組; 

2.map()

有返回值,可以return 出來。

arr[].map(function(value,index,array){

  //do something

  return XXX

})

參數:value數組中的當前項,index當前項的索引,array原始數組;

區別:map的回調函數中支持return返回值;return的是啥,相當於把數組中的這一項變為啥(並不影響原來的數組,只是相當於把原數組克隆一份,把克隆的這一份的數組中的對應項改變了);
var ary = [12,23,24,42,1]; var res = ary.map(function (item,index,input) { return item*10; }) console.log(res);//-->[120,230,240,420,10]; 原數組拷貝了一份,並進行了修改 console.log(ary);//-->[12,23,24,42,1]; 原數組並未發生變化

兼容寫法:

不管是forEach還是map在IE6-8下都不兼容(不兼容的情況下在Array.prototype上沒有這兩個方法),那么需要我們自己封裝一個都兼容的方法,代碼如下:
 
 
/** * forEach遍歷數組 * @param callback [function] 回調函數; * @param context [object] 上下文; */ Array.prototype.myForEach = function myForEach(callback,context){ context = context || window; if('forEach' in Array.prototye) { this.forEach(callback,context); return; } //IE6-8下自己編寫回調函數執行的邏輯 for(var i = 0,len = this.length; i < len;i++) { callback && callback.call(context,this[i],i,this); } } /** * map遍歷數組 * @param callback [function] 回調函數; * @param context [object] 上下文; */ Array.prototype.myMap = function myMap(callback,context){ context = context || window; if('map' in Array.prototye) { return this.map(callback,context); } //IE6-8下自己編寫回調函數執行的邏輯 var newAry = []; for(var i = 0,len = this.length; i < len;i++) { if(typeof callback === 'function') { var val = callback.call(context,this[i],i,this); newAry[newAry.length] = val; } } return newAry; } 
 


免責聲明!

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



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