被“遺忘”卻實用數組Array方法(indexOf、filter、forEach、map、reduce等等)

前言:最近學習Vue.js過程中用到了幾個很有用但是平時不常見的幾個操作數組的方法,這里就總結一下。

為了更方便的對JS中Array的操作,ES5規范在Array的原型上新增了9個方法
Array.prototype.indexOf  => 查找元素位置
Array.prototype.lastIndexOf => 查找元素位置
Array.prototype.every
Array.prototype.some => 檢測數組中的每一個元素,當callback返回true時就停止遍歷,并返回true
Array.prototype.forEach  => 數組遍歷 
Array.prototype.map  =>  map的作用是對原數組進行加工處理后并將其作為一個新數組返回
Array.prototype.filter  => 創建一個新的匹配過濾條件的數組。
Array.prototype.reduce
Array.prototype.reduceRight
我個人認為是最有用的,很多開發者都會碰到。

一、 indexOf()

indexOf()方法返回在該數組中第一個找到的元素位置,如果它不存在則返回-1。(ps:類似字符串的indexOf方法)
1) 數組內是字符串或者數字

不使用indexOf時

    var arr = ['apple','banana','pear'];
    var pos = null;
    for(var i=0;i<arr.length;i++){
        if(arr[i] == 'pear'){
            pos = i;
        }
    }
    console.log(pos);   //2

使用indexOf時

console.log(arr.indexOf("pear"));  //2
2) 數組里面是json(注意:對象在內存中是有自己的地址的)

例1:

    var arrJson = [];
    var json = {isChecked:false, title:"aaa"};
    arrJson.push(json);
    var json = {isChecked:false, title:"bbb"};
    arrJson.unshift(json);
    arrJson.push(
        {
            isChecked:false,
            title:"ccc"
        }
    );
    console.log(arrJson.indexOf(json));   //0  =>可以找到因為其在內存中地址一樣。
    console.log(arrJson.indexOf({isChecked:false, title:"ccc"}));//-1

例2:

    var person = { name: "Datura" };
    var people = [{ name: "Datura" }];
    var morePeople = [person];
    alert(people.indexOf(person)); //-1
    alert(morePeople.indexOf(person)); //0

二、 forEach(callback[thisArg])

forEach是用來替換for循環的。第一個參數是回調函數,是必選參數,第二個參數是一個對象,用來改變callback中的this指向,是可選參數。
例1:

var arr = [1,2,3,4,5,6,7,8,9];
    for(var i=0;i<arr.length;i++){
        console.log(arr[i]);
    }
    //
    arr.forEach(function (item,index) {  //第一個參數是元素,第二個參數是索引
        console.log(item);
    });

例2:

var arr = ['a','b','c'];
arr.forEach(function(item,index,obj){
    console.log(item,index,obj);
})
->
a 0 ["a", "b", "c"]
b 1 ["a", "b", "c"]
c 2 ["a", "b", "c"]

從輸出的接口可以看出,callback中傳入了3個參數item,index,obj 分別表示當前元素、當前位置、數組對象。再看看使用thisArg的情況
例3:

var obj = {
   fn:function(a,b){
       console.log(a,b);
   }
};
var arr = ['a','b','c'];
arr.forEach(function(v,i,a){
   this.fn(v,i);
},obj);

不傳thisArgs時,callback中的 this 默認指向window對象,當傳遞thisArg時,callback中的this就指向了thisArg,因此這個參數的目的就是為了改變回調函數中的this指向

三、 filter(callback[thisArg])

filter是過濾的意思,所以這個方法的作用就是返回一個匹配過濾條件的新數組,其接收兩個參數callback和thisArg, callback也是回調函數,主要用于對元素進行條件匹配,thisArg和forEach中的thisArg作用一樣,在這里就不重復了,看下面.
例1:

var arr = [
        {"name":"apple","count":2},
        {"name":"banana","count":1},
        {"name":"orange","count":3},
        {"name":"pear","count":5}
    ];
    var arrNew = [];
    for(var i=0;i<arr.length;i++){
        if(arr[i].name == 'orange'){
            arrNew.push(arr[i]);
        }
    }
    console.log(arrNew);

    var arrNew2 = arr.filter(function (item) {
        return item.name === "orange";
    });
    console.log(arrNew2)

例2:

var arr = ["a","b","a","c"];
var newArr = arr.filter(function(item){
     return item === "a";
});
      
newArr -> ["a","a"]

四、 map(callback[thisArg])

map()對數組的每個元素進行一定操作(映射)后,會返回一個新的數組,map()是處理服務器返回數據時是一個非常實用的函數。
例1:

//不使用map
    var arrFruit = [
        {
            "name":"apple",
            "count":3
        },
        {
            "name":"banana",
            "count":2
        },
        {
            "name":"orange",
            "count":4
        },
        {
            "name":"pear",
            "count":5
        }
    ];
    function getArrNew() {
        var arrNew = [];
        for(var i=0;i<arrFruit.length;i++){
            var item = arrFruit[i];
            item.newData = [item.name,item.count].join("剩余");
            arrNew[i] = item;
        }
        return arrNew;
    }
    console.log(getArrNew());
    function getArrNew2() {
        return arrFruit.map(function (item,index) {
            item.newData = [item.name,item.count].join("剩余");
            return item;
        });
    }
    console.log(getArrNew2());

例2:

var arr = [
   {w:10,h:10}, //定義長和寬
   {w:15,h:20},
   {w:12,h:12}
];
var newArr = arr.map(function(item){
   //根據長寬計算出面積并賦值給新屬性area 
   item.area = item.w * item.h;
   return item;
});
newArr[0] - > {w: 10, h: 10, area: 100}

可以看出,newArr返回的是增加了area屬性的對象數組。這個方法非常實用,一般情況下,當一個ajax請求返回時,我們都要對其結果集進行過濾和校驗等操作,這時map就派上用場了。我們再看看如果對map進行兼容性擴展:
例3:

if(!Array.prototype.map) {
   Array.prototype.map = function (callback, thisArg) {
       var temp = [];
       for (var i = 0; i < this.length; i++) {
           var newItem = callback.call(thisArg,this[i]);
           temp.push(newItem); //將callback返回的新元素壓入temp中
       }
       return temp;
   }
}

五、 reduce(callback[initialValue])

reduce()可以實現一個累加器的功能,將數組的每個值(從左到右)將其降低到一個值。
說實話剛開始理解這句話有點難度,它太抽象了。
場景: 統計一個數組中有多少個不重復的單詞 。
例1:

    //不使用reduce時
    var arr = ["apple","orange","apple","orange","pear","orange"];
    function getWordCnt(){
        var obj = {};
        for(var i=0;i<arr.length;i++){
            var item = arr[i];
            obj[item] = (obj[item] +1 ) || 1;
        }
        return obj;
    }
   // console.log(getWordCnt());

讓我先解釋一下我自己對reduce的理解。reduce(callback, initialValue)會傳入兩個變量。回調函數(callback)和初始值(initialValue)。假設函數它有個傳入參數,prev和next,index和array。prev和next你是必須要了解的。

一般來講prev是從數組中第一個元素開始的,next是第二個元素。但是當你傳入初始值(initialValue)后,第一個prev將是initivalValue,next將是數組中的第一個元素。
比如
例2:

    var arr = ["apple","orange"];
    function noPassValue(){
      return arr.reduce(function(prev,next){
        console.log("prev:",prev);
        console.log("next:",next);

        return prev + " " +next;
      });
    }
    function passValue(){
      return arr.reduce(function(prev,next){
        console.log("prev:",prev);
        console.log("next:",next);

        prev[next] = 1;
        return prev;
      },{});
    }
    //console.log(noPassValue());

    console.log(passValue());

例3:

var arr = [1,2,3,4];
var newArr = arr.reduce(function(previousValue, currentValue, currentIndex, array){
    console.log(previousValue, currentValue,currentIndex);
    return previousValue + currentValue;
},100);

100 1 0
101 2 1
103 3 2
106 4 3

newArr -> 110

從運行結果看,initialValue參數指定了previousValue的初始值,更重要的是,這次數組是從第1個位置開始遍歷,而不再是從第2個位置開始了。 現在回過頭來,對照這兩個例子,我相信你一定能夠理解reduce的作用了。下面對于reduce的擴展會鞏固你對reduce的理解:
例4:
if(!Array.prototype.reduce) {
Array.prototype.reduce = function (callback, initialValue) {
var previousValue = initialValue || this[0];//如果不指定intialValue,則默認為數組的第一個元素
//如果不指定initialValue,i從1開始遍歷,否則就從0開始遍歷
for (var i = initialValue?0:1; i < this.length; i++) {
//previousValue 累加每一次返回的結果
previousValue += callback(previousValue, this[i],i,this.toString());
}
return previousValue;
}
}

####六、 reduceRight(callback[initialValue])
reduce的作用完全相同,唯一的不同是,reduceRight是從右至左遍歷數組的元素。
####七、 some(callback[thisArg])
ome是`某些、一些`的意思,因此,some的作用是檢測數組中的每一個元素,當callback返回true時就停止遍歷,并返回true,這樣的描述似乎有些抽象,看代碼,一切盡在代碼中:
**例1:**

var arr = [ 1, 2, 3, 4];
var result = arr.some( function( item, index, array ){
console.log( item, index, array);
return item > 2;
});
->
1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]

restule -> true

從運行結果看,some檢測整個數組,只要當arr中有一個元素符合條件item>2 就停止檢測和遍歷,并返回true,以表示檢測到目標。這和我們在for循環中使用break語言的作用有點類似,這會兒你應該明白some的作用了吧! 下面對于some的擴展會有助于你對some的理解:
**例2:**

if(!Array.prototype.some) {
Array.prototype.some = function (callback, thisArg) {
for (var i = 0; i < this.length; i++) {
if(callback.call(thisArg,this[i],i,this.toString())){

           return true; //檢測到callback返回true,跳出循環,并返回true
       }
    }
    return false; //一個符合條件的都沒有檢測到,返回false
}

}

####八、 every(callback[thisArg])
every是`每一個`的意思,相比some來講,every對元素的檢測應該更加嚴格,那every到底是干什么的呢,看代碼就知道了:
**例1:**

var arr = [ 1, 2, 3, 4];
var result = arr.every( function( item, index, array ){
console.log( item, index, array );
return item < 3;
});

1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]

result -> false

從運行結果看,當檢測第3個元素時,item<2為false, 停止檢測,并返回false, 這說明every在檢測元素時,要求每一個元素都要符合條件item<3,如果有一個不符合就停止檢測,并返回false,(ps:你可以測試item<5時的運行結果,返回值一定是true). 那every到底有什么用武之地呢? 當一個for循環使用了break語句后,我們想知道for循環是否正常的執行完時, 我們一般會通過檢測for中的索引i==arr.length來判斷,因此every的作用就體現在這里。 我們再看看對于every的擴展:
**例2:**

if(!Array.prototype.every) {
Array.prototype.every = function (callback, thisArg) {
for (var i = 0; i < this.length; i++) {
if(!callback.call(thisArg,this[i],i,this.toString())){
return false; //檢測到不符合條件的元素,跳出循環,并返回false
}
}
return true; //所有元素都符合條件,返回true
}
}

####九.  forEach 與map的區別:
高級瀏覽器支持forEach方法
語法:forEach和map都支持2個參數:一個是回調函數(item,index,list)和上下文;
forEach:用來遍歷數組中的每一項;這個方法執行是沒有返回值的,對原來數組也沒有影響;
數組中有幾項,那么傳遞進去的匿名回調函數就需要執行幾次;
每一次執行匿名函數的時候,還給其傳遞了三個參數值:數組中的當前項item,當前項的索引index,原始數組input;
理論上這個方法是沒有返回值的,僅僅是遍歷數組中的每一項,不對原來數組進行修改;但是我們可以自己通過數組的索引來修改原來的數組;
forEach方法中的this是ary,匿名回調函數中的this默認是window;
**例1:**

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);//-->會對原來的數組產生改變;

map: 和forEach非常相似,都是用來遍歷數組中的每一項值的,用來遍歷數組中的每一項;
區別:map的回調函數中支持return返回值;return的是啥,相當于把數組中的這一項變為啥(并不影響原來的數組,只是相當于把原數組克隆一份,把克隆的這一份的數組中的對應項改變了);
不管是forEach還是map 都支持第二個參數值,第二個參數的意思是把匿名回調函數中的this進行修改。
**例2:**

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];

[完...]()
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容