美文网首页es6相关
被“遗忘”却实用数组Array方法(indexOf、filte

被“遗忘”却实用数组Array方法(indexOf、filte

作者: 诺奕 | 来源:发表于2017-04-06 09:33 被阅读515次

前言:最近学习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];

[完...]()

相关文章

网友评论

    本文标题: 被“遗忘”却实用数组Array方法(indexOf、filte

    本文链接:https://www.haomeiwen.com/subject/pspfattx.html