js數(shù)組中一些實用的方法(forEach,map,filter,find)

前言

您將在本文中學(xué)習(xí)到

for循環(huán)與forEach/map/filter/find的一個使用對比

同for循環(huán)性能的一個比較

是不是一提到循環(huán),就條件反射的只知道for循環(huán)呢,那么本文就是你想要知道的


1579435060211.png

需求場景: 假若后端返回這么一個json數(shù)據(jù)格式,如下所示,需要拿到返回對象中的數(shù)組項,或者根據(jù)某些指定的條件搔啊,取特定的值,然后渲染到頁面當(dāng)中去,例如拿name屬性值

{
   "ret":true,
    "data":{
       "headerTitle":"群成員",
       "members":{
          "A":[
           {"id":"0A1","name":"小愛","imgPhoto","http://default.png","phoneNumber":1333344,“age”:18
            },
         ],
          "B":[],
          "C":[],
          "D":[
            {"id":"0D1","name":"小兵","imgPhoto","http://default.png","phoneNumber":14343344,"age":19
            },
         ],
      "E":[],
      "F":[],
      "H":[
        {"id":"0H1","name":"黃藥師","imgPhoto","http://default.png","phoneNumber":14343344
        },],
      "L":[
          {"id":"0L1","name":"小 
  L1","imgPhoto","http://default.png","phoneNumber":14343344,"age":20},
          {"id":"0L2","name":"小L1","imgPhoto","http://default.png","phoneNumber":14343344,"age":22}
          {"id":"0L3","name":"小L2","imgPhoto","http://default.png","phoneNumber":14343344,"age":21}
  ]
  }
  }
}

對應(yīng)的UI圖

后臺數(shù)據(jù)返回給前臺,渲染UI效果.jpg

從數(shù)組對象中拿到特定的值渲染到頁面當(dāng)中螃成,一些新增的方法就很有用了,單純靠一個for循環(huán)就很難搞定了

目標:取對象中的值,然后循環(huán)遍歷數(shù)組

Es5實現(xiàn)方法:先通過對象,方式拿到數(shù)組對象,然后for循環(huán),拿到數(shù)組項

不同的框架代碼中實現(xiàn)的方式語法表現(xiàn)有些不一樣

Angular中

// array表示要遍歷的數(shù)組,obj表示遍歷時的每個元素,index表示遍歷數(shù)組的下標,當(dāng)然ng中提供 ng-repeat指令也是可以循環(huán)遍歷
angular.forEach(array,funciton(obj,index){
  // dosomething
}

React中:

react中父組件向子組件傳值,同樣,使用最多是map方法

Vue中

vue中比較粗暴,直接用指令v-for="item in items"可以遍歷,比較暴力
下面的是偽代碼,僅供參考

var members = {}; // 初始化一個空對象,用于接收后臺要返回的對象,然后通過DOM(innerHTML方式,字符串拼接)操作,將數(shù)據(jù)內(nèi)填充到頁面中指定的位置,當(dāng)然下面的是偽代碼模擬一下
axios.get("/api/mock/linker.json")
.then(res=>{
res = res.data;
if(res.ret == true){
let data = res.data;
this.members = data.members;
}
})
function showName(){
for(key in this.members){
  for(var i=0;i<members[key].length;i++){
    for(j in members[key]){
    console.log(members[key][j].name)
   }
      }
  }
}

}

如下一簡單示例所示:從對象中取某一數(shù)組中的某個值,從對象中取某一數(shù)組中的某個值,與上面的數(shù)據(jù)格式是一致的

var obj = {
"data":{
"members": [
   {"id":111,"name":"小高"},
   {"id":222,"name":"小凡"},
   {"id":333,"name":"小王"}
]
}
}
var newArrs= []; // 初始化一個空數(shù)組
for( key in obj.data){
//console.log(obj.data[key]);
for(let i = 0;i<obj.data[key].length;i++){
console.log(obj.data[key][i]);
for(j in obj.data[key][i]){
console.log(obj.data[key][i].name);
newArrs.push(obj.data[key][i].name);
// break;至于為什么會重復(fù)打印兩次,因為在里層for-in始終每次都得走一遍,然后在跳到上層for循環(huán),加上break的話,就跳出for-in循環(huán)了的,就達到目的了,這里可以瀏覽器打斷點看得出
}
}
}
console.log(newArrs);// (6) ["小高", "小高", "小凡", "小凡", "小王", "小王"]
console.log(new Set(newArrs)); // 去重,{"小高", "小凡", "小王"}
控制臺上打印輸出結(jié)果.jpg

js數(shù)組中的forEach實現(xiàn):

var obj = {
"data":{
"members": [
{"id":111,"name":"小高"},
{"id":222,"name":"小凡"},
{"id":333,"name":"小王"}
]
}
}
var newArrs= [];
obj.data.members.forEach(function(member,index,originArrs){
newArrs.push(member.name);
})
console.log(newArrs); //["小高", "小凡", "小王"]

forEach

功能: 循環(huán)遍歷數(shù)組中的每一項,只能遍歷數(shù)組
寫法:

數(shù)組對象.forEach(function(參數(shù)變量名1,參數(shù)變量名2胖腾,參數(shù)變量名3)){
// 做一些操作,forEach是沒有返回值,返回值為undefined
}) 

特點:
callback函數(shù)霍比,為數(shù)組中每個元素執(zhí)行的函數(shù)幕袱,該函數(shù)接收三個參數(shù)

  • 變量參數(shù)名1表示的是數(shù)組中的項值(數(shù)組當(dāng)前項的值)
  • 變量參數(shù)名2表示的是索引(數(shù)組當(dāng)前項的索引)
  • 變量參數(shù)名3表示原數(shù)組(數(shù)組對象本身)
    返回值:undefined,并且總是返回undefined值,并且不可鏈式調(diào)用
    使用場景:
    郵箱,QQ列表,全選:刪除所選項郵件等,todolist


    郵件中的列表.jpg

map

功能:循環(huán)遍歷數(shù)組中的每一項,也只能遍歷數(shù)組
寫法:

數(shù)組對象.map(callback(參數(shù)名1,參數(shù)名2,參數(shù)名3){
 // 對原數(shù)組做一些操作
}

特點:
map使用方式與forEach類似,callback回調(diào)函數(shù)接收的參數(shù)意義與forEach一致
但是它必須有返回值,如果不給return,它會返回一個undefined
return的返回值是什么,相當(dāng)于給這個新增的數(shù)組添加了新的值,但它不會影響原數(shù)據(jù),只是將原來的數(shù)組拷貝了一份,把拷貝的數(shù)組項進行更改
使用場景:
拷貝原數(shù)組,改變一些東西,假定有一個數(shù)組(A),將A數(shù)組中的值以雙倍的數(shù)值放到B數(shù)組中
Es5寫法

var numbersA = [1,2,3,4,5,6];
var numbersB = [];

for(var i = 0;i<numbersA.length;i++){
   numbersB.push(numbersA[i]*2);
}
console.log(numbersB)

Es6中map寫法

ar numbersA = [1,2,3,4,5,6];
var numbersB = []
var numbersC = numbersA.map(function(numberA,index,originArrs){
    return numbersB.push(numberA*2);
}
console.log(numbersA); // [1,2,3,4,5,6]
console.log(numbersB);// []
console.log(numbersC);// [4, 8, 12, 16, 20, 24]
console.log(numbersC==numbersA)

?在一個數(shù)組對象中拿到數(shù)組中對象的屬性

假定有一個對象數(shù)組(arrsA),將arrsA數(shù)組中對象某個屬性的值存儲到B數(shù)組中

var arrsA = [
             {name:"蘋果",price:8888,city:"舊金山"},
             {name:"金立",price:1100,city:"深圳"},
              {name:"小米",price:999,city:"北京"},
              {name:"錘子",price:888,city:"上海"}
             ]
var sum = 0;
var prices = arrsA.map(function(item,index,arr){
         console.log(item,index,arr);
         return item.price;
});
console.log(prices); // [8888,1100,999,888]
prices.forEach(function(price,index,arr){
    sum += price;
});
console.log(sum);

filter

功能:
經(jīng)過filter函數(shù)后會創(chuàng)建一個新的數(shù)組, 回調(diào)函數(shù)返回的結(jié)果一個boolean值,若結(jié)果為真,則返回匹配的項,若為假,則返回一個空數(shù)組,它不會改變原有數(shù)組,返回的是過濾后的新數(shù)組
寫法:

數(shù)組對象.filter(function(currentVal,index,arrs){
    // 做一些操作
}

特點:filter函數(shù)遍歷的元素范圍在第一次調(diào)用回調(diào)函數(shù)callback的時候就已經(jīng)確定了的,在調(diào)用filter之后添加到數(shù)組中的元素不會被filter遍歷到,如果已經(jīng)存在的元素被改變了悠瞬,則他們傳入callback的值是filter遍歷到他們那一刻的值,被刪除或從來未被賦值的元素不會被遍歷到们豌。
使用場景
示例1:假定有一個對象數(shù)組(A),獲取數(shù)組中指定類型的對象放到B數(shù)組中

假定有一個對象數(shù)組(A,persons),獲取數(shù)組A(這里指persons)中指定類型的對象放到B數(shù)組中

Es5實現(xiàn)
var persons = [
         {name:"小王",type:"boy",city:"廣西",age:15,height:170},
         {name:"小美",type:"girl",city:"北京",age:16,height:180},
         {name:"小高",type:"girl",city:"湖南",age:18,height:175},
         {name:"小劉",type:"boy",city:"河北",age:20,height:177}
 ]
         // Es5,假定要拿person數(shù)組對象中類型為boy的對象
         var filterPersons = [];
         for(var i = 0;i< persons.length;i++){
             if (persons[i].type == "boy"){
                filterPersons.push(persons[i]); // 若是想要拿到對象的鍵值,直接persons[i].屬性名
             }
         }
         console.log(filterPersons);

使用Es6中的filter實現(xiàn)
var persons = [
         {name:"小王",type:"boy",city:"廣西",age:15,height:170},
         {name:"小美",type:"girl",city:"北京",age:16,height:180},
         {name:"小高",type:"girl",city:"湖南",age:18,height:175},
         {name:"小劉",type:"boy",city:"河北",age:20,height:177}
 ]

var filterPersons = persons.filter(function(person,index,arrs){
             return person.type === "boy";
         })
         console.log(filterPersons)

控制臺顯示如下所示


filter使用場景1.png

示例2:假定有一個數(shù)組(A,persons)浅妆,過濾掉不滿足以下條件的對象
取出persons數(shù)組對象滿足類型為男孩望迎,age大于18的,小于等于20凌外,身高小于180辩尊,如果沒有匹配的它會返回一個空數(shù)組

var persons = [
         {name:"小王",type:"boy",city:"廣西",age:15,height:170},
         {name:"小美",type:"girl",city:"北京",age:16,height:180},
         {name:"小高",type:"girl",city:"湖南",age:18,height:175},
         {name:"小劉",type:"boy",city:"河北",age:20,height:177}
 ]
var filterNum = persons.filter(function(person,index,arrs){
    return person.type==="boy" && person.age > 18 && person.age<=20 && person.height<180
});
console.log(filterNum);// [{name: "小劉", type: "boy", city: "河北", age: 20, height: 177}]

示例3:?假定有兩個對象(A),根據(jù)對象A中id值,過濾掉B數(shù)組中不符合的數(shù)據(jù)(也就是根據(jù)某個條件,去抽取出要操作對象中的屬性)

var info =  {Id:4,content:"JavaScript"}

var languanges = [
        {Id:4,content:"Angular4"},
        {Id:2,content:"Vue.js",author:"尤大大"},
        {Id:3,content:"Node.js"},
        {Id:4,content:"React.js"}

]

var filterFun = function(info,languanges){
        return languanges.filter(function(laguange){
                     return laguange.Id === info.Id;
                })
            }
console.log(filterFun(info,languanges));//會挑選出languanges數(shù)組符合id等于4的選項,如果你想取對象中某個值,支持鏈式調(diào)用,直接跟著map或者forEach即可
如下鏈式調(diào)用
// 如下鏈式調(diào)用
var filterFun = function(info,languanges){
                return languanges.filter(function(laguange){
                     return laguange.Id === info.Id;
                }).map(function(currentVal){
                    return currentVal.content;
                }).forEach(function(curr){
                    console.log(curr);
                })
            }
console.log(filterFun(info,languanges)

這個filter方法有時會很有用,過濾掉某個對象中有沒有某個屬性值,有的話,就返回,沒有就返回一個空數(shù)組,如下所示:找到滿足laguanges數(shù)組對象中是否包含author的屬性
var filterFun = function(info,languanges){
                return languanges.filter(function(laguange){
                     return laguange.hasOwnProperty("author");
                })
            }
console.log(filterFun(info,languanges))

find

功能:用來查找目標元素,若找到就返回該元素,若找不到就返回undefined康辑,同樣不會改變原有數(shù)組
寫法:


數(shù)組.find(callback(參數(shù)1,參數(shù)2,參數(shù)3)

callback同樣接受三個參數(shù)
第一個參數(shù)1表示的是當(dāng)前遍歷到的元素摄欲,
第二個參數(shù)2表示的是,每一次迭代查找的數(shù)組元素的索引
第三個參數(shù)3表示的是原操作數(shù)組

特點
找到第一個符合條件之后,就不會往后找了,這與filter過濾是不一樣的,find方法比較快速便捷

返回值的是,若匿名回調(diào)函數(shù)結(jié)果為真,則返回所匹配的選項對象,若為假,則返回undefined

使用場景:
假定有一個數(shù)組對象(A),找到符合條件的對象

假定有一個對象數(shù)組(A),找到符合條件的對象,如下示例:找到learnWebs數(shù)組對象中name值為segementdefault

Es5實現(xiàn)

 var learnWebs = [
       {name:"segmentdefault"},
       {name:"MDN"},
       {name:"stackoverflow"},
       {name:"v2ex"},
       {name:"w3cplus"},
       {name:"segmentdefault"}
]
 var learnWeb = [];
 for(var i = 0;i < learnWebs.length; i++){
       if(learnWebs[i].name === "segmentdefault"){
        learnWeb.push(learnWebs[i]);
        //break;// 若不加break疮薇,都會走完一遍for循環(huán)
       }
 }
console.log(learnWeb);


使用Es6中的find實現(xiàn)
// Es6中的find方法,找到第一個符合條件之后的就不會往后在找了
var learnWebs = [
       {name:"segmentdefault"},
       {name:"MDN"},
       {name:"stackoverflow"},
       {name:"v2ex"},
       {name:"w3cplus"},
       {name:"segmentdefault"}
]

newWebs = learnWebs.find(function(learnWeb,index,orginArrs){
   return learnWeb.name ==="segmentdefault";
 })
 console.log(newWebs);

下面是find方法使用圖解胸墙,只要迭代器函數(shù)中找到匹配項了,就不會往下找了,結(jié)果為真就會返回所匹配選項對象,若結(jié)果為假,則返回undefined
[圖片上傳失敗...(image-25dce7-1580979324727)]

?示例2:假定有一個數(shù)組對象(A),根據(jù)指定對象的條件找到數(shù)組中符合條件的對象

假定有一個對象數(shù)組(A),根據(jù)指定對象的條件找到數(shù)組中符合條件的對象

例如:新聞列表,商品列表,博客文章等從商品列表數(shù)組對象中找到id,然后點擊id跳轉(zhuǎn)到詳情頁,從一個數(shù)組對象中找到對象中的某個id按咒,進行匹配操作

var goods = [
    {id:1,name:"鞋子",size:34,color:"red"},
    {id:2,name:"皮包",type:"愛馬仕"},
    {id:5,name:"手機",type:"iPhone6"}
]
var goodDetails = {id:5,desc:"我是手機詳情頁",price:666}

function showDetailFun(goods,goodDetails){
     return goods.find(function(good){
        return good.id===goodDetails.id;
     })
}
 console.log(showDetailFun(goods,goodDetails));


對應(yīng)的UI界面,點擊左邊的商品列表頁面,進入到商品對應(yīng)的詳情頁(博客,新聞都與這類似)
>### 同for循環(huán)的性能比較

這是一個容易引起撕扯的話題,筆者準備不進行大篇幅的介紹,結(jié)論先行,從兩個角度出發(fā):

**性能上**:for循環(huán)>forEach>map

**可讀性**: forEach/map>for循環(huán)

**區(qū)別**: for循環(huán)是按順序遍歷迟隅,按照下標索引的方式進行讀取訪問元素的,隨機訪問,而forEach/map等是使用iterator迭代器進行遍歷,先取到數(shù)組中的每一項的地止放入到隊列中,然后按順序取出隊里的地址來訪問元素

大體上講,如果數(shù)據(jù)量不是很大的情況下,拋開業(yè)務(wù)場景和使用便利性,單純談性能和效率是沒有意義的,一些Es5,ES6新增的數(shù)組迭代器方法方便了前端開發(fā)玻淑,使得以往復(fù)雜或者冗長的代碼嗽冒,可以變得易讀而且精煉

而好的for循環(huán)寫法,在大數(shù)據(jù)量的情況下补履,確實也有著更好的兼容和多環(huán)境運行表現(xiàn)

你可以使用console.time()以及console.timeEnd()進行測試的,個人覺得還是要多用Es5和Es6新增的迭代器方法,相比于for循環(huán),得定義初始值,得跟蹤循環(huán)計數(shù)的變量,是很容易出問題的

代碼是寫給人看的,順便在機器上運行添坊。從這一角度上講,個人支持多用Es5,Es6的迭代器方法,有時候在一些面試當(dāng)中,會問你這其中的一些性能比較的

雖然有些無聊,并不是糾結(jié)你用哪個,但更多的是考驗面試者的一個知識廣度的

結(jié)語

以上的forEach,map,filter,find,方法都是不改變原有數(shù)組的,當(dāng)然還有every,some等一些方法,forEach方法沒有返回值,默認返回值為undefined,所以它不支持鏈式調(diào)用箫锤,而map,filter方法會返回一個新的數(shù)組

find方法返回的根據(jù)迭代器函數(shù)結(jié)果boolean值贬蛙,若結(jié)果為真則返回指定的元素,若無則返回undefined

而改變原有數(shù)組的有:增加(push,unshift),刪除(pop谚攒,shift),reverse(顛倒),sort(排序)阳准,splice,限于篇幅所致,以后也會拿出來分享的,針對數(shù)組中的這些方法是非常值得反復(fù)學(xué)習(xí)研究的,用好了,它就是神器

對于同for循環(huán)的性能的比較,其實沒有多大的差異,還是要多用.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市馏臭,隨后出現(xiàn)的幾起案子野蝇,更是在濱河造成了極大的恐慌,老刑警劉巖括儒,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绕沈,死亡現(xiàn)場離奇詭異,居然都是意外死亡帮寻,警方通過查閱死者的電腦和手機乍狐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來固逗,“玉大人浅蚪,你說我怎么就攤上這事√陶郑” “怎么了惜傲?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長贝攒。 經(jīng)常有香客問我操漠,道長,這世上最難降的妖魔是什么饿这? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任浊伙,我火速辦了婚禮,結(jié)果婚禮上长捧,老公的妹妹穿的比我還像新娘嚣鄙。我一直安慰自己,他們只是感情好串结,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布哑子。 她就那樣靜靜地躺著舅列,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卧蜓。 梳的紋絲不亂的頭發(fā)上帐要,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音弥奸,去河邊找鬼榨惠。 笑死,一個胖子當(dāng)著我的面吹牛盛霎,可吹牛的內(nèi)容都是我干的赠橙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼愤炸,長吁一口氣:“原來是場噩夢啊……” “哼期揪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起规个,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤凤薛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后诞仓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缤苫,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年狂芋,在試婚紗的時候發(fā)現(xiàn)自己被綠了榨馁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片憨栽。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡帜矾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屑柔,到底是詐尸還是另有隱情屡萤,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布掸宛,位于F島的核電站死陆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏唧瘾。R本人自食惡果不足惜措译,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饰序。 院中可真熱鬧领虹,春花似錦、人聲如沸求豫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至最疆,卻和暖如春杯巨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背努酸。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工服爷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚊逢。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓层扶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親烙荷。 傳聞我的和親對象是個殘疾皇子镜会,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容