【Array - 数组】
其实在ECMAScript中,除了Object外,Array类型恐怕是最常用的类型了。如果你是一个工作过一两年的前端人,那你一定能体会得到Array的实用性。同时,你也一定发现了,其实ECMAScript中规定的数组和其他大多数语言中的数组有着很大的区别,这个区别就是:ECMAScript数组的每一项可以保存任何类型的数据。(就是说萝卜,青菜,辣椒,字符串,数值,对象等等都可以)
在总结有关Array的所有方法之前,我们先来回忆一下有关Array的一些最基础也是最重要的知识点:
上面这个例子,足够说明两个有关Array的知识点:
1、创建数组有两种方式(一种是构造函数,一种是字面量表示法)
2、数据的length属性是可读可写,可以随时增减,从而控制数组元素数量。
上面这两点,是我们开始使用数组的根基,接下来就是本文要说的重点。
在JavaScript代码中,几乎每一次代码中,我们都需要通过使用一些方式方法去处理它,从而得到我们想要的结果,这些方式方法,各种各样,各自有各自的特点和用法,在这里,不管是复习还是学习,小郑给大家总结一下,ECMAScript中所有关于数组的处理方式。
先来看一下张表:
这是控制台打印出来的数组原型上的一些方法,还没有显示完,看的出来,数量多,下面我大致将这些个方法做了一个分类。不会每一个都列出来说一遍,有些新的方法在其它的文章中也说到过,所以这里,主要会挑一些最最基础最最重要的来详细阐述。
将所有相关方法总共可分成5类:转换,栈,队列,重排,操作。因为方法很多,包括新标准方法的出现,难免会有一些方法被遗漏,但是我想到的,一定会详细的讲清楚,而且,尽量将一些常用的数组相关方法都写到。
重要说明:为了让了手速度能跟上思维,大部分举例我都会通过chrome控制台完成。有不适应者,请适应。
一、转换方法
数组中有关转换的方法我所知道的总共有四个:toLocaleString()、toString()、valueof()、join()。
其中前面三个是继承对象的方法,也就是说所有对象都具有的方法。而且在数组中,这三个方法返回结果几乎是一样的:返回以逗号分隔的字符串。
1、toString() && valueof() && toLocaleString()
举个例子:
如上图所示,valueOf返回的是原数组形式,其它两个方法返回以逗号分隔的字符串。当然,这也不是说toString和toLocaleString方法输出总是相同,他两之间也是有区别的。区别在于Locale这个词。
2、toLocaleString() && toString()
比如用这两个方法来显示当前地区的时间日期格式,如下:
如上图结果,toString方法返回的是默认格式,toLocaleString返回的是当前地区的时间日期格式。再比如在美国,toLocaleString方法有可能返回的就是07/20/2018 7:00:17。总之,就是这么个意思。接下来说一下join这个方法。
3、join()
与上面三个方法不同的是,如果使用join()方法,则可以使用不同的分隔符来构建这个字符串。
使用语法:array.join(separator)
separator是连接字符串的分隔符,可以为空。来看一下例子:
关于转换方法需要注意的一点是:如果数组中的某一项的值是null或者undefined,那么该值在join(),toLocaleString(),toString()返回的结果中以空字符串表示,valueOf()方法会按原值以数组的形式输出。
举个例子:
关于Array(数组)中的转换方法小结一下:总共有四个方法(toLocaleString()、toString()、valueof()、join()),大部分情况下toLocaleString和toString输出结果是相同的,但也不完全相同,valueOf方法是以数组的形式输出,而join则可以使用不同的分隔符来构建字符串。最后需要注意的一点是,当数组里有值为null或者undefined时,方法的输出为空或者原值。
二、栈方法
ECMAScript数组提供了一些个让数组行为类似于其它数据结构的方法,如,这里要说的栈。方法就两个push()和pop()。在讲这两个方法前先来看一下什么是栈。
首先,栈是一种LIFO(last-in-first-out,后进先出)的数据结构,也就是说,最新添加的项是最早被移除的,且栈中所有项的推入和弹出,只发生在一个位置,这个位置就是栈顶。有栈顶就会有栈底,那么这个LIFO具体是个什么过程了,下面我画了两张图来解释一下推入和弹出的整个过程。
1、推入
也就是数组元素入栈的整个过程。下面这张图足够说明这个过程了。
上图演示,从空栈到依次入栈1,2,3。最后到得到一个拥有三个元素的栈。栈顶永远都是指向最后一个入栈的元素。下面断续来了详细了解一下弹出的过程。
2、弹出
也就是数组元素出栈的整个过程。同样给大家画了一张图,我觉得用图,更好让自己记住,印象深刻。
如上图演示从一个拥有三个元素的栈,逐个取出元素,到最后变成一个空栈。出栈时,从最后一个入栈的元素开始到第一个入栈的元素。这就是所谓的后进先出。
好了,现在搞清楚了出栈和入栈的具体过程,那接下来看一下这两个过程是怎么用方法来实现的。
3、方法实现(pop/push)
ECMAScript分别提供了两个方法来实现推入栈(push)和弹出栈元素(pop)这两个动作。
那么,这两个方法的具体使用细节也是非常值得我们去一一搞明白的。下面跟着我来理一下。
【讲一下push(item)】
把一个或多个参数item附加到一个数组的尾部,并返回修改后数组的长度。这句话可以记住
举个例子:
同学们,请仔细看一下上面这个例子,我觉得此刻你至少得关注三个点:1、原数组a已经改变了(为什么这个点值得我们注意了?那是因为在接下来内容里我会说到一个concat方法,这是与其的区别点)。2、返回的是新数组的长度。3、当参数是一个数组的时候,它会把参数数组作为单个元素整个添加到数组中。
【讲一下pop(item)】
移除Array中的最后一个元素并返回元素。这句话可以记住
注:如果该Array是empty,它会返回undefined。
这个例子足够证明了定义的准确性。如上:移除元素c,并返回该元素。
好了 ,小结一下,ECMAScript数组提供了两个方法(pop,push),可以使得array可以像堆栈一样工作。关于栈,它有元素推入和弹出两个动作,那么,这两个动作的具体过程,我用图的方式解释清楚了(如:怎么理解LIFO)。最后,用举例的方式说了一下pop和push的使用。
三、队列方法
队列和栈区别在于,栈的访问规则是LIFO,而队列的访问规则是FIFO(first-in-first-out,先进先出)。在列表的末端添加项,从列表的前端移除项。
同样,在讲队列相关方法之前,先来图形化解释一下什么是入队和出队。看一下这两个操作的具体过程,也就是FIFO的实现。
1、入队
上面这张图,重点关注一下队首和队尾的箭头指向。其中,队尾(红色箭头)是指向新入队的元素。上图从一个空队列变成了一个拥有三个元素的队列。演示了元素入队的过程。
2、出队
上面这张图,同样重点关注一下队首和队尾的箭头指向,1最先入队,所以它最先出队,出队依次是1,2,3。这就是FIFO原则。
现在清楚了出队和入队的过程,脑子里有了一个印象。下面我们来讨论一下处理出队和入队的方法。
3、方法(shift/unshift)
从栈的过程,可以得知,push相当于就是实现了入队,而出队是从第一个入队元素开始的。ECMAScript提供了一个方法shift。
【讲一下shift()】
说到shift方法,必须先说一"正向队列"的概念,简单理解为右控制进(用方法push),左控制出(用方法shift)。如下图所示:
shift方法的概念:移除数组array中的第1个元素并返回该元素。这句话可以记住
注意:如果这个数组array是空的,它会返回undefined。
上面代码中:a数组的第一个元素'a'已经被移除,返回给c的就是这个被移除的元素'a'。
有移除就会有添加。在数组的前端添加元素,ECMAScript提供了一个方法unshift。
【讲一下unshift(item)】
这个方法的用途与shift相反,它能在数组前端添加任意个项并返回新数组的长度。这句话可以记住
从用途上来看,它和pop方法会形成一个反向队列的形式。简单理解为左控制进入(用方法unshfit),右控制出(用方法pop),如下图所示。
注意,这个方法是把item插入到array的开始部分而不是尾部。它返回array的新的length。
这个例子中,数组a前面插入了两个元素'?',‘@’。而返回的是变量r,为数组的长度5。
来小结一下队列:队列和栈不一样,栈是后进先出,而队列是先进先出,在数据结构一头的"进出"这个动作在栈里已经有两个方法实现了( push&pop),这里ECMAScript给队列"出"提供了方法shift。与push方法结合,形成了一个正向队列,实现了从队尾进队首出的逻辑,同时也提供了一个unshift,与pop方法结合,形成了一个反向队列,实现了从队首进队尾出的逻辑。
四、重排序方法
数组的重排序,有两个方法,sort和reverse。其中reverse比较简单,sort相对来说复杂一点。
【讲一下reverse】
用于颠倒数组中元素的顺序。
var values = [1,2,3,4,5]
values.reverse()
console.log(values)
// 5,4,3,2,1
【讲一下sort】
为什么说这个方法相对来说比较复杂了? 我们先来认识一下这个方法。
sort方法有以下几个特性:
1、默认sort方法是按升序排列数组项,也就是小的在前面,大的在后面。
2、sort()方法比较的是字符串。
3、精确的说,sort()方法是按照字符编码的顺序进行排序。(数组项会经过toString转型后在比较)。
4、可以接收一个比较函数作为参数。
来,举个例子,从实例中看问题。
var values = [0, 1, 5, 10, 15]
vlaues.sort()
console.log(values)
// 0, 1, 10, 15, 5
然而,出现10在5的前面,是因为按字符编码来比较时'10'位于'5'的前面,所以会出现这样的排序结果,但这样的结果排序可能在实际应用中并没有太大的用处。从用途上来看,用的比较多的可能是数值类型的排序比较。我们给sort定义一个参数函数来处理一下。
比较函数有两个参数,如果第一个参数应该位于第二个参数之前则返回一个负数,如果两个参数相等则返回0,如果第一个参数应该位于第二个之前则返回一个负数。
values.sort(compare)
console.log(values)
// 0, 1, 5, 10, 15
这会输出的结果还算满意,另外,关于比较函数需要知道两个知识点:
第一,竟然可以按升序,也可以让它产生降序输出结果
将比较函数中的return 1与return -1调一下就行。
第二,如果只是比较数值类型,包括valueOf返回数值类型,可以简化比较函数。
function compare(value1, value2) {
return value2 - value1
}
第三,因为有了一个可以自定义的比较函数,所以我们其实可以创造一些更智能比较函数。这个点后面可以单独来深入写一下。
好了,关于重排序的方法其实就说了两个,reverse&sort。reverse会经常用到,sort貌似用的不是很多,至少我没有经常用到过。使用的时候一定要注意它的4个特性。
五、操作方法
数组的操作方法有三个:concat,slice,splice。这三个我觉得都非常重要,都不难理解。
【讲一下concat(item)】
concat返回的是一个新数组,如果参数item是一个数组,那么它的每个元素会被分别添加。直接举一个例子来看一下就全明白了。
数组a并不会改变(这个push是有区别的),只是实现了一份浅复制。当item是一个数组的时候,会将每一个元素添加到后面,如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾。
【讲一下slice(start, end)】
在上篇中,详细写过字符串的slice方法,这里需要区分开来理解。数组中实现一段浅复制,主要有以下几个关注点:
1、start是必需,end默认是数组的长度,可以没有。
2、返回start到end之间的项,但不包括结束项。
3、当参数中有负数时,就用数组长度加上负数作为对应位置上的参数。
看一个例子:
关于负参数的处理办法:假如在一个包含5项的数组上调用slice(-2, -1)与调用slice(3, 4)得到的结果是相同的,如果结束位置小于起始位置,则返回空数组。
【讲一下splice】
这个方法非常强大,它有很多种用法。它的用途是向数组的中部插入项。
splice(start, deleteCount, item...)
功能一:删除
可以删除任意数量的项,只需指定2个参数,要删除的第一项的位置和要删除的项数。
如splice(0, 2)表示删除数组中的前两项。原数组少两项,返回的是删除的项。
功能二:插入
可以向指定位置插入任意数量的项,只需提供3个参数:起始位置,0(要删除的项数),要插入的项。如果要插入多个项,可以再传入第四,第五,以至任意多个项。
如下实例:
var colors = ['red', 'green', 'blue']
var removed = colors.splice(1, 0, 'yellow', 'orange')
console.log(removed) // 空数组 返回的是删除的项 这里是0
console.log(colors)
// ["red", "yellow", "orange", "green", "blue"] 从位置1开始插入两项
功能三:替换
可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定3个参数:起始位置,要删除的项数和要插入的任意数量的项。
var colors = ['red', 'green', 'blue']
var removed = colors.splice(1, 1, 'yellow', 'orange')
console.log(removed) // ['green'] 返回的是删除的项 这里是1
console.log(colors)
// ["red", "yellow", "orange", "blue"] 从位置1开始插入两项
【最后总结也重要】
一开始说了一下数组的最重要的基础用法知识点,然后将数组的方法分成5类来分别总结对应的方法。这5类是转换方法,栈方法,队列方法,重排方法,操作方法。转换方法涉及到的方法有4个:toLocaleString()、toString()、valueof()、join(),分别讲了下它们的用法和之间的区别。栈方法涉及到的方法有2个:push、pop。需要注意推入栈和弹出栈的详细过程。队列方法涉及到的方法有2个:shift、unshift。不仅需要知道入队和出队的过程,还需要知道与栈方法结合形成的正向队列和反向队列是怎么回事。重排方法涉及到的方法有2个:reverse、sort。其中sort的几个特性及参数函数的用法一定要理清。最后一个是操作方法涉及到三个比较重要的方法:concat、slice、splice。重点是关注一下它们的使用。当然,数组的方法远不止这么多,如map、reduce、reduceRight......。这里先说这么多。
领取专属 10元无门槛券
私享最新 技术干货