被“遗忘”却实用数组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阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容