天花乱坠的数组方法(一)

      数组是 JS 当中很重要的一个部分,它有很多很多很多的方法,对于我这样记性不好的人来说,一些不常用的方法经常会被遗忘,经常需要再次查找才能想起来。今天为了能给自己加深对数组方法的记忆,将通过两个章节去整理下常用的数组方法。第一个章节将记录下 ES6 中常见的数组方法,其中将详细记录下部分数组,第二个章节将简单整理下 ES5 之前的数组方法。

ES6 中新增的数组方法

数组元素遍历:for 循环/forEach()

在 ES6 之前还没有 forEach()方法时,我们通常是使用 for 循环对数组进行遍历的。

ES5 之前:for 循环遍历数组实例:

1
2
3
4
5
//通过for循环将数组中的元素遍历出来
var color = ['blue','yellow','red'];
for(var i=0;i<color.length;i++){
console.log(color[i]); //blue,yellow,red
}

有了 forEach()方法后,数组的遍历整体变得更加可观,直接用数组调用对应的内容

forEach()遍历数组实例:

1
2
3
4
5
var colorES6 = ['blue','yellow','red','white'];
//forEach()中放一个迭代函数,colorES6作为形参去接受数组里的每一个内容
colorES6.forEach(function(colorES6){
console.log(colorES6); //blue,yellow,red,white
});
forEach()遍历数组的优点:
1
2
3
4
5
6
7
8
9
//求数组元素的总和
var numbers = [1,2,3,4,5];
var sum = 0; //用于接收数组的总和
//forEach可以将函数抽离出来
function num(number){
sum+=number;
}
numbers.forEach(num);
console.log(sum); //15

以上代码我们可以看出 forEach()的好处不止让代码变得更加可观,可以直接调用数组里的内容,还可以将函数抽离出来

forEach()遍历数组的过程:

为了能加深对 forEach()的理解,可以用一个流程图来简单画出 forEach()遍历数组的过程:


forEach()遍历数组过程

      图中画的是”forEach()遍历数组实例”中的过程:第一次先将blue放在迭代器里,将它打印出来,第二次再将yellow放在迭代器里,将它打印出来,以此类推。 直达找到最后一个没有的时候,那么当前的循环就结束了。

forEach()使用的场景:

比如:一个表单有一个多选框,再提交表单时,需要遍历选中的元素并进行相应操作。

数组的映射:map()

映射这两个字大家可能会觉得有点抽象,通俗点来说就是对数组进行一些转化。常用的场景有两种:
1.在拷贝数组的过程中改变一些东西
2.在数组中拿到一些固定的属性
接下来我将用for循环和ES6新方法map()编写上面两种场景

场景一:将数组A以两倍的形式放到数组B中去

ES5之前:for循环+push()实现场景一
1
2
3
4
5
6
var oldA = [1,2];
var oldB = [];
for(var i=0;i<oldA.length;i++){
oldB.push(oldA[i]*2); //将数组A中的元素乘以2后放置到数组A中
}
console.log(oldB); //[2,4]
map()实现场景一
1
2
3
4
5
6
var arrA = [1,2,3];
//map返回的就是数组,所以不需要 var arrB =[];
var arrB = arrA.map(function(x){ //map里面依旧放迭代器函数
return 2 * x;
});
console.log(arrB); //[2,4,6]

场景二:有一个对象数组A,把数组A中对象的name属性存储到对象B上

ES5之前:for循环+push()实现场景二
1
2
3
4
5
6
7
8
9
var oldarrObjectA = [
{name: "Lucy",age: 13},
{name: "Tom",age: 14}
];
var oldarrObjectB = [];
for(i=0;i<oldarrObjectA.length;i++){
oldarrObjectB.push(oldarrObjectA[i].name);
}
console.log(oldarrObjectB); //["Lucy", "Tom"]
map()实现场景二
1
2
3
4
5
6
7
8
9
var arrObjectA = [
{name: "Lucy",age: 13},
{name: "Tom",age: 14},
{name: "Lili",age: 15}
];
var arrObjectB = arrObjectA.map(function(x){
return x.name;
});
console.log(arrObjectB); //["Lucy", "Tom", "Lili"]

map()和forEach()一样,里面放的都是迭代器函数。map()返回的是一个新的数组。这里我们需要注意一下map()是需要返回值的,如果不给返回值,则默认返回undefined

1
2
3
4
5
6
// 不给map返回值
var arrA = [1,2,3];
var arrB = arrA.map(function(x){
2 * x;
});
console.log(arrB); //[undefined, undefined, undefined]

map()映射数组的过程:

接下来,我们用一个流程图来简单画出场景一中map()映射数组的过程:


map()映射过程

      场景一中A数组想要做的事情就是让B数组中装的是它的两倍,map里面的方法会拥有一个迭代器函数。比如a.map(),它会将a中的每个值放到迭代器函数中的形参里面,然后将值乘以2后返回到新数组中。例如拿到”1”后,乘以2再返回到新数组中去。

使用场景:

      例如:基金产品中会有很多种基金,我们假设每个基金都是一个对象,每个基金都会有很多属性:比如基金名字、关注度、收益率等。后台人员需要获取每个基金的关注度时,就可以采取map()方法。

数组的过滤:filter()

过滤数组是我们开发中经常会遇到的问题,接下来我会使用三个常见的场景加深对filter()方法的理解

场景一:

把不想要的值过滤掉,拿出我们想要的值(假定有一个对象数组A,获取数组中指定类型的对象放到数组B中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//将typeA中为男性的对象抽取出来
var typeA = [
{name: 'Lily',gender: 'female'},
{name: 'Lucy',gender: 'female'},
{name: 'Peter',gender: 'male'},
];
// ES5之前:for循环+push()的实现
var typeB = [];
for(var i=0;i<typeA.length;i++){
if(typeA[i].gender==='male'){
typeB.push(typeA[i]);
}
}
console.log(typeB); //[{name: "Peter", gender: "male"}]
// ES6 filter()的实现
var typeC = typeA.filter(function(x){
return x.gender==='male'; //[{name: "Peter", gender: "male"}]
});
console.log(typeC); //{name: "Peter", gender: "male"}

场景二:

假定有一个对象数组A,过滤掉不满足以下条件的对象:
条件:性别女,年龄大于13岁,班级不为3班的

1
2
3
4
5
6
7
8
9
var personA = [
{name: 'Lily',gender: 'female',age:16,class:1},
{name: 'Lucy',gender: 'female',age:14,class:2},
{name: 'Peter',gender: 'male',age:17,class:3},
];
var choosePerson = personA.filter(function(x){
return x.gender === 'female' && x.age>13 &&x.class !==3
});
console.log(choosePerson); //[{name: "Lily", gender: "female", age: 16, class: 1},{name: "Lucy", gender: "female", age: 14, class: 2}]

场景三:

根据对象A的id值,过滤掉B数组中与对象A中id值不符的元素

1
2
3
4
5
6
7
8
9
10
var objA = {id:1,title:'haha'};
var filterId = [
{id:1,content:'filter'},
{id:2,content:'filter'},
{id:1,content:'filter2'}
];
filterId = filterId.filter(function(x){
return x.id === objA.id;
});
console.log(filterId); //[{id: 1, content: "filter"},{id: 1, content: "filter2"}]

filter()过滤数组的过程:

看了以上三个场景后,对filter的使用方法应该有所了解了,接下来,我们结合场景一看看filter是怎样实现过滤的


场景一filter过滤过程

      当我们在遍历数组typeA时,会将当前类型的值放到迭代器函数里面,去对它进行匹配,因为我们拿到的是每个对象,当每个对象下的gender值为male时,则为匹配成功,会以return true的形式返回,并放到typeC数组中。如果匹配不成功,则返回false,且不会放到typeC数组中。

数组的查找:find()

通过find()方法可以帮我们找到对应的东西。还是根据两个常用的场景来看看find()怎么用吧。

场景一:

假定有一个对象数组,找到符合条件的对象并存储起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//快速找到findA中姓名为'Billy'的对象
var findA = [
{name: 'Lucy'},
{name: 'Peter'},
{name: 'Billy'}
];
var thisA;
//ES5之前:for循环
for(var i=0;i<findA.length;i++){
if(findA[i].name === 'Billy'){
thisA = findA[i];
break; //找到之后结束循环,避免浪费时间
}
}
console.log(thisA); //{name: "Billy"}
//ES6 find():找到第一个符合条件的对象,就不会再次循环
var thisB = findA.find(function(x){
return x.name === 'Billy'
});
console.log(thisB); //{name: "Billy"}

场景二:

假定有一个对象数组,根据指定对象的条件找到数组中符合条件的对象

1
2
3
4
5
6
7
8
9
10
11
12
var findArr = [
{name: 'Lucy',age: 13},
{name: 'Billy',age: 17},
{name: 'Peter',age: 13}
];
var choosefindArr ={name: 'Bob',age: 13};
function choose(findArr,choosefindArr){
return findArr.find(function(x){
return x.age === choosefindArr.age;
});
}
console.log(choose(findArr,choosefindArr)); //{name: "Lucy", age: 13}

find()的工作流程:

find()的特点在于:找到对应的条件,就不会继续往下执行。能帮助我们快速查找到对应的内容。接下来,我们根据场景1来看看它的工作模式是什么样的吧


场景一find工作流程

      当我们遍历findA这个数组通过find()时,会将每个name放到迭代器函数中,去判断目前的name和我们想要的name是否相等。如果不相等,则会返回一个false,就没有任何东西;如果相等,则返回true,并将对应的内容返回到thisA中。

一真即真,一假即假的:every()、some()

every()所有条件都满足,才返回true;some(),只要一个条件满足,就返回true()。

场景一:

查询班级成员成绩达标情况,成绩大于60表示达标,小于60为不达标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var classMark = [
{name: 'Lucy',mark: 90},
{name: 'Peter',mark: 80},
{name: 'Billy',mark: 20}
];
//ES5之前:for循环 方法
var markeveryOK = true; //成绩全部达标
var marksomeOK = false; //成绩部分达标
for(var i=0;i<classMark.length;i++){
if(classMark[i].mark < 60){
markeveryOK = false;
}else{
marksomeOK = true;
}
}
console.log(markeveryOK,marksomeOK); //false true
//every()/some()方法;
//成绩全部达标,一旦返回的是假,后续的东西就不会再去遍历了
var markeveryOKES6 = classMark.every(function(x){
return x.mark > 60;
});
//成绩部分达标,一旦返回的是真,后续的东西就不会再去遍历了
var marksomeOKES6 = classMark.some(function(x){
return x.mark >60;
});
console.log(markeveryOKES6,marksomeOKES6); //false true

场景二:

一个表单页面,判断所有输入框内容的长度是否大于0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 获取输入框的内容
function Field(value){
this.value = value;
}
// 判断当前输入框内容的长度是否大于0
Field.prototype.validate = function(){
return this.value.length > 0;
}
var filedName = new Field('Lucy');
var filedage = new Field('');
var filedpassword = new Field('123456');
var fieldArr = [filedName,filedage,filedpassword];
// 用every方法判断是否所有输入框内容的长度都大于0
var result = fieldArr.every(function(x){
return x.validate();
});
console.log(result); //false

every()的工作流程:

every()的特点:一旦返回的是假,就不会再去遍历了。接下来我们结合场景一简单说下every()的工作流程


场景一every工作流程

      学生的成绩分别是:90,80,20。我们首先把”90”放到迭代器函数中,然后和我们的60进行匹配。90不小于60,所以markeveryOKES6为true。20小于60,所以markeveryOKES6为false。最终会将返回值用&&运算符输出,即一假即假。
some()

some()的工作流程:

every()的特点:一旦返回的是真,就不会再去遍历了


场景一some工作流程

      第一次把90放到迭代器函数中,marksomeOKES6为true。当some()返回为true时,则不再进行遍历。即一真即真

把数组聚合成结果 reduce()

reduce()可以替代大多数数组的方法,比如forEach、map()等,接下来我们看看它是怎么替代和应用的

场景一:

代替forEach()计算数组中所有值的总和

1
2
3
4
5
var reduce =[10,20,30];
var sum = reduce.reduce(function(x,y){
return x+y;
},10); //这里放初始值
console.log(sum); //70

场景二:

代替map()将数组中对象的某个属性抽离到另外一个数组中

1
2
3
4
5
6
7
8
9
10
var reduceArr =[
{name:'Lucy',age:11},
{name:'David',age:19},
{name:'Billy',age:13}
];
var choosereduceArr = reduceArr.reduce(function(x,y){
x.push(y.name);
return x;
},[]);
console.log(choosereduceArr); // ["Lucy", "David", "Billy"]

场景三:

判断字符串中括号是否对称
例如:
((())) 对称
()()() 对称
((() 不对称

1
2
3
4
5
6
7
8
9
10
function bracket(string){
// 先将字符串变为数组
return !string.split('').reduce(function(x,y){
if(y === "("){++x;};
if(y === ")"){--x;};
return x;
},0);
}
console.log(bracket('(())')); //true
console.log(bracket('(())))))')); //false

reduce()的工作流程:

接下来我们结合场景一看看reduce()是如何把数组聚合成结果的吧


场景一reduce工作流程

      场景一中reduce arr是10、20、30,当我们在遍历的时候,这个参数的初始化值为10,然后我们拿到的就是10+20,然后第二个值就为20,然后再次与迭代器函数里的值相加,以此类推得到最后一个结果。

reduceRight()

从字面很好理解,reduce()遍历的顺序是从左往右,相反它的从右往左。和redece()的区别就是遍历顺序。这里就不多做解释了。

数组的检索indexOf()

该方法将根据我们查找的对象,从头到尾的去检索数组,返回我们查找对象的位置

1
2
3
4
5
6
7
var arr = [1,2,3,-1,2,3];
console.log(arr.indexOf(2)); //1
console.log(arr.indexOf(99)); //-1
console.log(arr.indexOf(1,0)); //0
console.log(arr.indexOf(2,2)); //4
console.log(arr.indexOf(2,-1)); //-1
console.log(arr.indexOf(2,-3)); //-4

从以上的例子可以总结下indexOf()的使用方法
indexOf(i,p)会返回从p位置开始检索的对象i,检索完成后返回对象i在数组中的位置
i:必传参数,查找的对象
p: 可传参数,从数组的哪个位置开始找

数组的检索lastndexOf()

indexOf的区别就是,lastIndexOf是从右往左找的。

1
2
3
4
var arr = [1,2,3,-1,2,3];
console.log(arr.lastIndexOf(2)); //4
console.log(arr.lastIndexOf(1,0)); //0
console.log(arr.lastIndexOf(2,-1)); //4

数组的检索indexOf()

该方法将根据我们查找的对象,从头到尾的去检索数组,返回我们查找对象的位置

1
2
3
4
5
6
7
var arr = [1,2,3,-1,2,3];
console.log(arr.indexOf(2)); //1
console.log(arr.indexOf(99)); //-1
console.log(arr.indexOf(1,0)); //0
console.log(arr.indexOf(2,2)); //4
console.log(arr.indexOf(2,-1)); //-1
console.log(arr.indexOf(2,-3)); //-4

从以上的例子可以总结下indexOf()的使用方法
indexOf(i,p)会返回从p位置开始检索的对象i,检索完成后返回对象i在数组中的位置
i:必传参数,查找的对象
p: 可传参数,从数组的哪个位置开始找

判断是否为数组 isArray()

我们来回顾下原先没有isArray()的时候,我们通常是怎么判断是否为数组的

1
2
3
4
var obj = [1,2,3,-1,2,3];
console.log(Object.prototype.toString.call(obj)); //[object Array]
console.log(obj instanceof Array); //true
console.log(obj.constructor === Array); //true

有了isArray()后,我们可以直接使用这个方法来判断数组啦~

1
2
3
4
var obj = [1,2,3,-1,2,3];
var obj2 = {name:'Lucy'};
console.log(Array.isArray(obj)); //true
console.log(Array.isArray(obj2)); //false

以上篇幅有些长,主要介绍了ES6新增的一些常用数组,接下来第二篇,将简单回顾下ES5一些数组的常用方法吧~

Copyright ©2019 guowj All Rights Reserved.

访客数 : | 访问量 :