鍍金池/ 問答/HTML/ 應(yīng)該用forEach改變數(shù)組的值嗎?

應(yīng)該用forEach改變數(shù)組的值嗎?

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

下面就是簡單的例子。

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

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

forEach:

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

map:

arr = arr.map((item) => {   //  有同事指出應(yīng)該聲明一個新變量來存儲map的結(jié)果,這個建議我認(rèn)為是對的。
    item.a = 3;
    return item;
});
回答
編輯回答
咕嚕嚕

網(wǎng)絡(luò)上找了一點兒關(guān)于這個的一些比較和介紹,希望對你有所幫助!

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

共同點:

1、都是循環(huán)遍歷數(shù)組中的每一項。

2、forEach()和map()里面每一次執(zhí)行匿名函數(shù)都支持3個參數(shù):數(shù)組中的當(dāng)前項item,當(dāng)前項的索引index,原始數(shù)組input。

3、匿名函數(shù)中的this都是指Window。

4、只能遍歷數(shù)組。

1.forEach()

沒有返回值

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

  //do something

})

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

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);//--> 通過數(shù)組索引改變了原數(shù)組;  

2.map()

有返回值,可以return 出來。

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

  //do something

  return XXX

})

參數(shù):value數(shù)組中的當(dāng)前項,index當(dāng)前項的索引,array原始數(shù)組;

區(qū)別:map的回調(diào)函數(shù)中支持return返回值;return的是啥,相當(dāng)于把數(shù)組中的這一項變?yōu)樯叮ú⒉挥绊懺瓉淼臄?shù)組,只是相當(dāng)于把原數(shù)組克隆一份,把克隆的這一份的數(shù)組中的對應(yīng)項改變了);
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];  原數(shù)組拷貝了一份,并進行了修改
console.log(ary);//-->[12,23,24,42,1];  原數(shù)組并未發(fā)生變化

兼容寫法:

不管是forEach還是map在IE6-8下都不兼容(不兼容的情況下在Array.prototype上沒有這兩個方法),那么需要我們自己封裝一個都兼容的方法,代碼如下:
 
/** 
* forEach遍歷數(shù)組 
* @param callback [function] 回調(diào)函數(shù); 
* @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下自己編寫回調(diào)函數(shù)執(zhí)行的邏輯  
    for(var i = 0,len = this.length; i < len;i++) {  
        callback && callback.call(context,this[i],i,this);  
    }  
}   
 
/** 
* map遍歷數(shù)組 
* @param callback [function] 回調(diào)函數(shù); 
* @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下自己編寫回調(diào)函數(shù)執(zhí)行的邏輯  
    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;  
}  

希望我的回答對你有所幫助!

2017年2月12日 05:43
編輯回答
舊酒館

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

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

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

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

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

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

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

2018年5月25日 11:30