数组作为javascript中最常用的数据类型之一,掌握好数组的方法在日常的开发中是非常有必要的,javascript中的数组相比其他语言来说更灵活,因为数组的每一项都可以是不同的数据类型,可以是对象,数组,字符串,数值等等,接下来一点一点的了解吧!
1.数组的创建
说到数组首先肯定是创建,只有创建或者声明一个变量是数组之后才可以使用它,以及他的一些属性和方法。数组的创建有两种方式,即,构造函数式和数组字面量式。
第一种构造函数式创建,利用new Array来创建,下面先上一段例子:
1
分析一下,第一行创建了一个空数组;第二行创建了一个长度为3的空数组,注意这个3是数组的长度为3,不是数组的第一项是数值3,切记!在下一篇讲到的类数组方法Array.of()方法就可以创建数值3;第三个是创建了一个字符串数组,里面只有一个值;第四行,第五行都目前chrome浏览器无法编译通过,写法有问题,特意列出来注意一下。 在使用Array 的时候new也可以省略,其效果也是一样的。
第二种是数组字面量创建数组,即直接用[]。
1
再分析一下,第一行也是创建了一个空数组;第二行创建了一个长度为2的数组,数组中包含12,34,在有的浏览器中长度为3,注意一下。第三行创建了一个长度为4的空数组,数组的每一项值是undefined,有的浏览器也可能数组的长度是5。第四行创建了一项含有字符串的数组;第五行创建一个全是数值的数组,最后一行创建了一个长度为4的数组,每一项都是不同的数据类型。
注意: 1. var arr = new Array(,,,,);是报错的,而var arr = [,,,,];是可以创建数组的;以及var arr = new Array(12,34,)也是报错的,而var arr = [12,34,]是可以的,这些注意不要搞混淆了,日常工作中都不推荐此种方法创建数组; 2. 虽然两种方法都可以创建数组,但是数组字面量要比构造函数的性能好,原因是:json格式的语法浏览器引擎能直接解析,而new Array需要调用Array的构造器。日常工作中可以使用前者,方便快速省性能。
2. length属性
大家都知道length属性表示数组的长度为多少,现在用构造函数式和数组字面量式创建一个长度为10的空数组,试试看:
1
现在用数组的length属性来操作数组的长度,不用arr.pop()和arr.shift()方法怎么来搞呢?
1
分析一下:首先arr1 是一个长度为10的数组,当把数组的长度成为8的时候,此时会从数组的第一个元素开始向后截取8个作为数组的新值,此操作会改变数组。 arr2是一个长度为2的数组,将数组的长度设为100后,将依次为数组的剩余97项设置值为undefined,当再改变某一项的元素的时候就是正常的赋值了,最后一个给数组添加一项,当前数组的最后一项的索引是length-1,当arr.length就是添加一项。
3.数组的检测
数组作为引用类型之一,检测方法有两种:instanceof和isArray。其中instanceof适用于在一个网页或者一个全局作用域的情况比较实用,随着前端框架越来越多,在项目 中引入太多的框架的时候,每个框架对数组可能进行过二次封装,这样导致一个问题就是instanceof 返回的结果可能会不同,使用时得注意,基本用法如下:
1
基于以上的问题,ES5又新增了新的检测方法,isArray 来确定某个值到底是不是数组,而不用管其他的作用域问题。写法如下:
1
4.类栈操作相关
数据结构栈的特点就是后进先出(LIFO, last-in-first-out) ,比喻成容器罐好理解点,最后放的在上面,拿的时候也先从上面拿,操作推入和弹出,都发生在栈的顶部,javascript数组中有专门的方法push()和pop()来模拟栈的操作。
push()方法,接受不限制个数的参数,在数组的末尾插入元素,返回值是修改后的数组的长度,此方法会改变原数组;
pop()方法,不接受参数,从数组的末尾来删除最后一个元素,返回值是删除的元素,此方法也会改变原数组。下面我们来看看具体用法:
1
5.类队列操作相关
上面聊完了栈,现在来看看队列,相信这两个词大家都不陌生,队列的特点是:先进先出(FIFO , first-in-first-out),看做是一个空的管道比较好理解,从一端进入,另一端出去。javscript数组提供了shift()和push()方法来模拟队列的特点。
shift() , 从数组的头部删除一个元素,返回值是删除的元素,此方法会改变原数组,看看使用情况:
1
跟shift()方法结果刚好相反的是unshift()方法,shift()是从数组头部删除元素,而unshift()刚好是从头部添加元素,接受不限个数的参数,返回值是改变后的数组的长度,此方法会改变数组,其实,这个方法效果跟push()一样,只不过一个在数组前面插入,一个在后面插入,看看效果:
1
6.数组的重排序方法
说到数组的重排序方我们肯定想到的是reverse()和sort()方法,来了解一下这两个方法,首先:
reverse()方法是将数组进行反转,调换顺序,比较简单哈,返回结果是改变顺序后的数组,此方法会改变原数组。
1
即返回的结果就是原数组改变后的结果,二者是相等的,但是这个方法只能反转不方便啊,比如说我想把数组按照升序或者降序排列,reverse就干不了,这时候就得用到sort()方法了。
sort()方法,默认是按照升序排列的,返回的结果也是改变后的数组,此方法会改变原数组。
1
首先,同学们可能会疑问,怎么返回的结果跟我预想的不一样呢,不应该是[0 , 1 , 5, 10 ,15 , 10000000]吗?这是因为当调用sort()方法的时候,首先sort()会把数组的每一项值都先调用toString()方法变成对应的字符串,即['0','1','10000000','15','10','5'];第二步再进行字符串的比较,挨个字符比较。上一篇《一篇文章搞定javascript中的字符串》我讲过字符串的比较方法,不了解的回过去看一下哈,然后得出结果[0, 1, 10, 10000000, 15, 5]。
这里同学可能就有疑问,我就想要结果[0 , 1 , 5, 10 ,15 , 10000000]。也不是不可以,这时候我们可以使用sort()方法的参数来进行处理,此方法接受一个比较函数来作为一个参数,里面我们可以自定义我们想要的结果,是想让升序呢,还是降序都可以实现。
1
是的,我们想要的结果得到了,这里解释一下compareArray,次方法作为sort()方法的参数,接受两个参数,分别是要比较的数组的两项,返回结果是三种,大于0 ,小于0,或者等于0.然后sort根据返回的结果,如果小于零则不用换位置,如果大于零则需要调换位置,等于零则代表相等,不做处理,进行下一次的比较。
前面我们看了升序的写法,那么降序也是一样的,只不过把返回值调换一下就可以了。
1
看着一个数组的比较,写了这么多的代码,有没有高级写法,简写的让自己的代码看起来更有逼格一点呢,当然有啊,这里我们用到ES6来改写一下:
1
简单明了,这是升序的结果,如果想要降序用item2 - item1就可以。这里稍微解释一下,第一,箭头函数是原始函数的简写,方便轻巧,第二,当箭头函数中代码块中只有一行语句并且包含return时,可以省略{}和return。关于ES6后面的文章中我会在后面的文章中写,记得关注。
7.数组的转换方法
数组的转换方法有三个toString(),toLocaleString(),valueOf().
toString(),将数组转换成字符串 ,返回值是改变后的字符串,此方法不会改变数组。
1
toLocaleString(),在有的时候,结果和toString()一样,当然也不总是 一样,,这得跟当地的编码有关,使用时也得注意,此方法转换时每一项都调用toLocaleString()。
1
在我们地区,超过三位以上的数字会以 ’,‘ 隔开的。所以得到的结果会和toString()不同。
valueOf(),该方法是数组对象的默认内置方法,返回Array对象的原始值,该原始值由Array对象派生的所有对象继承,此方法不会改变原数组。
1
注意:所有的对象含有toString(),toLocaleString(),valueOf()这三个内置方法,并不是数组独有。
8.数组的操作方法
concat():顾名思义,连接,将一些数组拼接到一起形成一个新的数组,此方法不改变原数组。可以接受任意多个参数,参数可以是数组,字符串,数值都可以。当不传参数的时候只返回原数组的副本。
1
slice():即截取,接受一个或者两个参数,第一个参数是要截取的起始项,第二个参数是截止项。当只有一个参数的时候,默认是从起始项到数组末尾,该方法返回的是一个新数组,不改变原数组。
1
当slice的参数中含有负数的参数的时候,则用数组的长度+负参数作为新的参数值再开始截取,计算后的第二个参数比第一个参数小时,则返回的是一个空数组。
1
splice(): slice 是截取数组,而splice是向数组中插入元素或者删除元素,或者替换元素,参数的个数的不同起到的作用也不同。
1.删除元素,两个参数,第一个是起始位置,第二个是要删除的个数。此方法会改变原数组,返回值是删除的新数组,不改变原数组。
1
2.插入元素,三个参数,第一个参数是起始位置,第二个参数删除的个数为0,第三个是要插入的元素,如果要插入多个项,则会有第四个,五个参数,总之,从第三个开始都是要插入的项数,返回值是[],会改变原数组。
1
3.替换元素,三个以上的参数,其中第二个参数不能为0,否则就是插入元素了,先删除后替换。返回值是删除原数组的元素所组成的数组
1
分析一下,首先是从第三个开始删除了两项,得到[4,5],然后再在此位置上插入了三项,删除项和替换项不一定要相等。
9. 查找位置相关的方法
javascript数组提供查找位置的方法有两种,indexOf()和lastIndexOf(). 查找的时候当数组中有重复的元素是只返回首次出现的元素的位置。
1.indexOf(): 如果在数组中能查找到则返回其索引值,如果找不到则返回-1。此方法接受两个参数,第一个参数是要查找的元素,第二个参数是查找的起始位置, 如果没有第二个参数则默认从0开始查, 如果第二个参数是负数的话,则将其作为数组末尾值得一个抵消,即-1表示从最后一个元素开始向后查找,-2表示从倒数第二个元素查找。 如果第二个参数大于数组的长度,表示 已经超出查找范围了,直接返回-1。一直都是从前向后查找,跟参数是不是 负数,查出范围没关系,此方法不会改变原数组。
2.lastIndexOf(): 与indexOf()不同的是这个方法是从后向前查找,其他的都一样。
1
10.数组的迭代方法
数组的迭代在ES5中是有5个,分别是every,filter,forEach,map,some,这五个方法接受两个参数,第一个是函数,是要作用在数组的每一项上面的函数,第二个参数是作用域对象,可选,默认是this即数组对象本身。第一个参数函数接受三个参数,分别是数组的每一项,第二个是索引,第三个是当前的数组。下面分别来看一下其含义和用法:
every() : 英文意思,简单理解是每一个,即作用在数组每一项上面的函数的返回都为true的时候,Array.every才返回true,此方法不会改变原数组。看一个例子,有一个学生的成绩数组,判断是不是都及格了,看看怎么写:
1
filter() : 过滤,即把符合指定条件的过滤出来,比较简单,看看例子,把及格的学生筛选出来:
1
forEach() : 遍历数组的每一项然后进行后续的逻辑操作 , 此方法没有返回值。
1
map() : 遍历整个数组的每一项,返回指定操作后的结果。
1
some() :此方法跟every()不同的是,every只有都满足条件的时候才返回true ,some是只要有一个满足条件就返回true。every 类似于 && ,而some 类似于 ||。看个例子,查看班级里面有没有成绩超过90分的同学,并且计算有几个:
1
11.数组的缩小方法
ES5中提供了两个数组缩小的方法,reduce()和reduceRight(), 两个方法都会遍历数组的所有项,然后返回一个操作后的最终结果。这两个方法都接受两个参数,第一个,作用在数组项上的函数,第二个,是 作为缩小基础的初始值,可选。
reduce() : 接受四个参数,分别是前一个值(prev),当前值(cur),索引 (index),以及当前数组本身(array),参数名字随便起。当reduce的第二参数有值的时候,第一次遍历的时候,函数的的第一个参数(prev)就是这个初始值,没有值时,第一次遍历的时候前一个值(prev)和当前值(cur)分别是数组的前两项。有点斐波那契数列的感觉,遍历的时候是从前向后。来看一个字符串拼接操作应用:
1
reduceRight() : 和reduce唯一不同的是从后向前遍历,类似于indexof和lastIndexOf()的查找顺序,一个前面开始,一个从后面开始。
1
好了,ES5数组的所有的方法已经讲完了,总共9大类,23个函数,你都了解了吗?
下一篇文章,我会讲述ES6中对数组的加成,新增了哪些方法,以及定型数组,类数组和类数组的所有方法