资讯专栏INFORMATION COLUMN

用好JS 原生API系列之数组

shenhualong / 2782人阅读

摘要:函数的因为也拥有属性,所以其被称为类数组对象。方法数组的拼接,,指被拼接的对象数组,为数组。如果为负,则将其视为,其中为数组的长度。而提供了数组反转和排序来对数组进行重排序。用好原生,你的代码将显得干净,有趣。

前言

最近工作做数据交互展示,常和数据打交道,而随之而来的就是遇见后端传来的各种各样的数组,我需要用各式各样的方法来变换这些数据,来最好的展示这些数据;很多东西久了没用就容易忘,自己也是边查边用,这篇文章算是自己这一周学习的知识的总结。当然你也可以打看MSDN查看更标准的叙述

数组原生的API

那些需要知道的特性:
1:数组在JS中是对象的一种,所以数组也是引用类型,所以操作时要小心,时刻记住你操作的不是一个普通类型;
2:每个数组都自带一个length属性,这个属性很特别,可读也可写。JS函数的arguments因为也拥有length属性,所以其被称为类数组对象。
这里不会提到所有的API,因为真的太多了。我只提我最近常用的,还有被人们常说的增删查改。

API之增删查改

我以前听说增删查改(CRUD),是sql语言。但有一次参加面试,面试官问:说说你知道的JS数组增删查改,那数组的增删查改是那些呢?说真的,当时我一脸懵逼,我还以为数组还能用sql语句操作
增加:push,unshift,还有通常我们常用的arr[arr.length] = newChild;
首先我们有一个数组arr= [1,2,3,4,5,6]
push被称为栈操作,即栈顶入,栈顶出,所以当我们采用arr.push(7),得到的结果是arr= [1,2,3,4,5,6,7],其相对于arr[arr.length] = 7;
unshift和push相反,即栈底入,所以当我们做和上面相似的操作,即arr.push(7),得到的结果是arr= [7,1,2,3,4,5,6]
至于arr.push(3.5)和arr.unshift(3,5)答案是多少,你可以自己亲自尝试一下;
删除:pop(对应push),arr.pop()操作后,arr是arr= [1,2,3,4,5];shift(对应unshift),arr.shift()操作后,arr= [2,3,4,5,6];操作length,当我们arr.length = 4操作后,得到 arr =[1,2,3,4];
这里提一句,使用delete arr[arr.length-1],并不能删除最后一个元素,而只是将最后一个元素的赋值去除,值为undefined,且其length未变.
查:很多时候我们都采用for循环遍历加比较,来查找某个元素在数组中的索引,但其实js是支持indexOf方法的,当我们进行arr.indexOf(3),其会返回结果2,进行arr.indexOf(9),其返回的结果就是-1,和字符串的indexOf方法何其相似,所以也有相对应的lastIndexOf()方法;
改:改在数组操作中很常用,也很直接,这个就不长述了。
这里说三个重要的方法concat,slice和splice,concat主要做数组拼接(我经常用它做数组的深拷贝);slice主要做数组截取,而splice几乎能完成上述所有的CUD操作,之所以要把他们分开提,是因为这两个方法操作较复杂,其cancat与slice并不是对数组本身的操作,而是会产生一个新的Array数组,被操作的数组并没有改变;而splice方法,是直接对数组进行操作,仅当参数删除或替换元素操作时,会返回一个新的数组,其包含的元素就是返回的元素。
concat方法:数组的拼接,array.concat([item1[, item2[, . . . [, itemN]]]]) ,array指被拼接的对象数组,item为数组。但我用的最多的就是数组的深拷贝,看实例:

var hege = ["Cecilie", "Lone"];
var stale = ["Emil", "Tobias", "Linus"];
var kai = ["Robin"];
var children = hege.concat(stale,kai);
console.log(children)  //打印["Cecilie", "Lone","Emil", "Tobias", "Linus","Robin"]
var deepArr = stale.concat([]);//数组深拷贝;
deepArr.push("Denzel"); 
console.log(deepArr); //打印["Emil","Tobias", "Linus","Denzel"]
console.log(stale); //打印["Emil", "Tobias", "Linus"];

slice方法:arrayObj.slice(start, [end]),从方法的描述可知,其可接受两个参数,start即截取开始的位置,end截取结束的位置,参数可选,如果没有,截取的位置是直到数组末尾,但需要注意的是,start位置的元素是被截取的,而end位置的元素是不包含的,只截取该元素前一个元素。

var arr= [1,2,3,4,5,6]
var newArr = arr.slice(0,arr.length);
console.log(newArr)  //打印 [1,2,3,4,5,6]
newArr = arr.slice(3,5);
console.log(newArr)  //打印 [4,5]

其实前面都不复杂,复杂的是参数为负的时候,规则是这样的(来源于MSDN):如果 start 为负,则将其视为 length + start,其中 length 为数组的长度。如果 end 为负,则将其视为 length + end,其中 length 为数组的长度。如果省略 end,则将一直提取到 arrayObj 的结尾。如果 end 出现在 start 之前,则不会将任何元素复制到新数组中。

var arr= [1,2,3,4,5,6]
var newArr = arr.slice(0,-1);
console.log(newArr)  //打印 [1,2,3,4,5]
newArr = arr.slice(-3,-1);
console.log(newArr)  //打印 [4,5]

splice方法:arrayObj.splice(start, deleteCount, [item1[, item2[, . . . [,itemN]]]]),相比slice,其复杂太多,所以几乎能完成所有的cud操作,但与其不同的是,上面的方法都只能在数组的头和尾上进行操作,splice能完成任意位置的cud操作;其arrayObj参数为必需,且必须是一个 Array 对象;start参数必需,指数组中移除元素操作的起点,从 0 开始,deleteCount参数必需,指要移除的元素的个数,上面提到的返回数组,其数组元素的个数与deleteCount相等,当deleteCount=0时,其返回一个空数组;item1, item2,. . ., itemN可选,指插入数组中代替已移除元素的元素。直接看实例吧:

let arr =[1,2,3,4,5,6]  //以下三步是独立操作,非连续操作。偷了个小懒
arr.splice(2, 2, "11","12"); //这个操作删除了3,4,并在其位置上添加了11,12,相当于改,其结果[1, 2, "11", "12", 5, 6]

arr.splice(2,0, "11","12");//这个操作删除了0个元素,添加了11,12,相当于增,其结果[1, 2, "11", "12",3,4,5,6];

arr.splice(2,2, );//这个操作删除了2个元素,添加了0个元素,相当于删,其结果[1, 2, "11", "12",3,4,5,6],相当于增加;  

splice方法的start参数也支持负数,其会自动类加length,直到为正。

API之重排序

说道数据处理,也许你利马会想到排序,什么冒泡,差值,希尔,快速排序算法。而JS提供了reverse()数组反转和sort()排序来对数组进行重排序。
数组反转reverse():和其名字描述的一致,用于数组反转,需要注意的是,其是对数组本省的操作,并不会产生新数组;很简单,看个示例就明白了:

var color =["a","b","e","d","c","f"];
color.reverse();
console.log(color);//打印[f,c,d,e,b,a]

数组排序sort():这里所说的排序,并不是狭义的有序排列,你可以利用这个方法把有序的数组进行无序排列,为啥?应为sort()方法支持你自己写比较函数。另外,在没有比较函数的情况下,sort()方法是根据每个数组项的toString()后根据字典顺序进行排序的;

var color =["a","b","e","d","c","f"];
color.sort();
console.log(color);//打印[a,b,c,d,e,f]   
var num =[1,3,2,12,24,5,7,19];
num.sort(); //这将证明上面提到的根据每个数组项的toString()后根据字典顺序进行排序
console.log(num);//打印[1, 12, 19, 2, 24, 3, 5, 7]

如果你想让上面的数据进行升序或者降序进行排序,你需要自己写一个比较函数,即这样:

var num =[1,3,2,12,24,5,7,19];
num.sort(function(a,b){
    return a-b;
});   
console.log(num);//打印[1, 2, 3, 5, 7, 12, 19, 24]
num.sort(function ()  //让有序变成乱序
{
    return Math.random()<0.5?1:-1;
});
console.log(num);//打印[3, 5, 2, 1, 7, 19, 12, 24]    
API之循环遍历

也许你已习惯了for循环,或者你对jquery的each方法已经产生了依赖,或许你应该接触点新知识了,毕竟ES6已经不算新了;ES7已经开始被支持了;而你还不知道用ES5的map,some,every,filter来循环遍历你的数组,甚至是forEach。
every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true;
some():对数组中的每一项运行给定函数,如果该函数任一项都返回true,则返回true;
所以,纵向看,其实every是所有项的&&操作,而some是||操作;
filter():对数组中的每一项运行给定函数,返回该函数该返回true的项组成新的数组;
map():对数组中的每一项运行给定函数,返回该函数该返回true的项组成新的数组;
forEach():功能类似于for循环;
对于上面5个方法,都有类似的回调参数(item,index,array),试着从一个例子来了解他们,一个简单的例子显得有些苍白。假如现在我们有这样一个需求,已知某个四川省某个景区今日接待旅客总人数10000人,然后从购票信息获取到前十名的省份和人数,我们想计算这些省份每个所占比例,并把他们的人数用一个数组多带带保存下来,用来找最大值,最小值,我们试着不用for循环来解决这个问题;

var totle = 10000;
var data = [{name:"四川省",num:3000},
    {name:"重庆市",num:500},
    {name:"江西省",num:900},
    {name:"湖南省",num:600},
    {name:"陕西省",num:800},
    {name:"河北省",num:300},
    {name:"湖北省",num:400},
    {name:"北京市",num:600},
    {name:"云南省",num:400},
    {name:"湖南省",num:300}];
var tempArr = [];
data = data.map(function (item) {
    tempArr.push(item.num);
    item.percent = item.num/totle;
    return item;
})
console.log(tempArr); //[3000, 500, 900, 600, 800, 300, 400, 600, 400, 300]
console.log(data); //0:{name: "四川省", num: 3000, percent: 0.3} 1:{name: "重庆市", num: 500, percent: 0.05}......

短短四行代码就完成了这两个需求,如果我们只想要第2名到第9名的数据(即去掉一个最高分,去掉一个最低分)拿来做分析,所以根绝前面抽离出来的数组,我们再借助sort()和filter()来完成这个需求:

tempArr.sort(function (v1,v2) { // 降序排列
    return v2-v1;
});
var max = tempArr.shift(),min = tempArr.pop();
data=data.filter(function (item) {  //这个方法并没有完全达到需求,这里只是演示filter的用法,你可以试着优化这个函数,来完成这个需求
    return (item.num!==max)&&(item.num!==min)
})
console.log(tempArr);  //体会一下shift和pop[900, 800, 600, 600, 500, 400, 400, 300]
console.log(data);   //0:{name: "重庆市", num: 500, percent: 0.05} 1:{name: "江西省", num: 900, percent: 0.09}打印出来,结果只剩下7个了,因为最小值出现了两次。

通过上面两个例子,也许你应该已经体会到了这些原生数组API的作用了,他们在数据处理中,优势非常大,但也不能说,以后就可以完全不依赖ofr循环了,还是很难,上面五个方法有一个通病,就是无法中止遍历,即在循环中break,break一些遍历查找中,还是相当省时,这也是为啥有时我们还是需要for循环来做一些操作. 至于some,every,foreach,你可以自己动手感受一下。
别总是沉溺于已会的那点知识,别总依赖框架,插件。用好原生API,你的代码将显得干净,有趣。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88412.html

相关文章

  • 2017年1月前端月报

    摘要:平日学习接触过的网站积累,以每月的形式发布。年以前看这个网址概况在线地址前端开发群月报提交原则技术文章新的为主。 平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 概况 在线地址:http://www.kancloud.cn/jsfront/month/82796 JS前端开发群月报 提交原则: 技...

    FuisonDesign 评论0 收藏0
  • 2017年1月前端月报

    摘要:平日学习接触过的网站积累,以每月的形式发布。年以前看这个网址概况在线地址前端开发群月报提交原则技术文章新的为主。 平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 概况 在线地址:http://www.kancloud.cn/jsfront/month/82796 JS前端开发群月报 提交原则: 技...

    ivyzhang 评论0 收藏0
  • 2017年1月前端月报

    摘要:平日学习接触过的网站积累,以每月的形式发布。年以前看这个网址概况在线地址前端开发群月报提交原则技术文章新的为主。 平日学习接触过的网站积累,以每月的形式发布。2017年以前看这个网址:http://www.kancloud.cn/jsfron... 概况 在线地址:http://www.kancloud.cn/jsfront/month/82796 JS前端开发群月报 提交原则: 技...

    CloudwiseAPM 评论0 收藏0
  • 原生js练习题---第四课

    摘要:然而问题是,这个法则在导航条的主体是可行的但是子选单因为前面提到的三层嵌套构造圆角,已经无法减少嵌套了,同时还得考虑到子选单也是嵌套在导航条里的啊。。。同理,反过来进入子选单时自然就用来抵消达到筛选的目的。 0x1setTimeout应用 实现效果:4-01setTimeout应用 又见导航条,先看下css,这里用的是雪碧图背景做出圆角的效果,虽然是经典的方法、兼容性好,但这种代码写起...

    Snailclimb 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<