目录
数组原型提供的方法非常之多,主要分为三种,一种是会改变自身值的,一种是不会改变自身值的,另外一种是遍历方法。
基于ES6,改变自身值的方法一共有9个,分别为pop、push、reverse、shift、sort、splice、unshift,以及两个ES6新增的方法copyWithin 和 fill。
一、栈方法:
数组对象可以像栈一样,也就是一种限制插入和删除项的数据结构。栈是一种后进先出(LIFO, Last-In-First-Out)的结构,也就是最近添加的项先被删除。数据项的插入(称为推入,push)和删除(称为弹出,pop)只在栈的一个地方发生,即栈顶。ECMAScript数组提供了push()和pop()方法,以实现类似栈的行为。
1、pop
(1)pop()方法删除一个数组中的最后一个元素,同时减少数组的length值, 并且返回这个元素。如果是栈的话,这个过程就是栈顶弹出。
(2) 由于设计上的巧妙,pop方法可以应用在类数组对象上,即 鸭式辨型. 如下:
(3) 但如果类数组对象不具有length属性,那么该对象将被创建length属性,length值为0。如下:
var o = {0:"cat", 1:"dog", 2:"cow", 3:"chicken", 4:"mouse"};
var item = Array.prototype.pop.call(o);
2、push
push()方法添加一个或者多个元素到数组末尾,并且返回数组新的长度。如果是栈的话,这个过程就是栈顶压入。
(1)语法:arr.push(element1, …, elementN)
(2) 同pop方法一样,push方法也可以应用到类数组对象上,如果length不能被转成一个数值或者不存在length属性时,则插入的元素索引为0,且length属性不存在时,将会创建它。
var o = {0:"football", 1:"basketball"};
var i = Array.prototype.push.call(o, "golfball");
(3)实际上,push方法是根据length属性来决定从哪里开始插入给定的值。
利用push根据length属性插入元素这个特点,可以实现数组的合并,并且合并后第二个数组合并到第一个数组中,即第一个数组变成新的数组,第二个数组不会发生改变。
例子如下:
二、排序方法:
数组有两个方法可以用来对元素重新排序:reverse()和sort()。顾名思义,reverse()方法就是将数组元素反向排列。
1、sort
sort()方法对数组元素进行排序,并返回这个数组。
(1)语法:arr.sort([comparefn])
-
comparefn是可选的,如果省略。
-
数组元素将按照各自转换为字符串的Unicode(万国码)位点顺序排序。
-
默认情况下,sort()会按照升序重新排列数组元素,即最小的值在前面,最大的值在后面。为此,
因此,sort()会在每一项上调用String()转型函数,然后比较字符串来决定顺序。即使数组的元素都是数值,也会先把数组转换为字符串再比较、排序。比如:
一开始数组中数值的顺序是正确的,但调用sort()会按照这些数值的字符串形式重新排序。因此,即使5小于10,但字符串"10"在字符串"5"的前头,所以10还是会排到5前面。很明显,这在多数情况下都不是最合适的。为此,sort()方法可以接收一个比较函数,用于判断哪个值应该排在前面。
comparefn比较函数接收两个参数,如果第一个参数应该排在第二个参数前面,就返回负值;如果两个参数相等,就返回0;如果第一个参数应该排在第二个参数后面,就返回正值。下面是使用简单比较函数的一个例子:
function compare (v1,v2){
if(v1<v2){
return -1;
} else if (v1>v2) {
return 1;
} else {
return 0;
}
}
在给sort()方法传入比较函数后,数组中的数值在排序后保持了正确的顺序
这个比较函数也可以简写为:
values.sort((a,b)=> a<b ? 1: a>b ? -1 : 0);
(2)如果数组的元素是数值,或者是其valueOf()方法返回数值的对象(如Date对象),这个比较函数可以直接写为:
function compare (v1,v2){
return v2 - v1;
}
(3)同上, sort一样受益于鸭式辨型,比如:
注意:使用sort的鸭式辨型特性时,若类数组对象不具有length属性,它并不会进行排序,也不会为其添加length属性。
2、reverse
reverse()方法颠倒数组中元素的位置,第一个会成为最后一个,最后一个会成为第一个,该方法返回对数组的引用。
(1) 语法:arr.reverse()
var array = [1,2,3,4,5];
var array2 = array.reverse();
console.log(array); // [5,4,3,2,1]
console.log(array2===array); // true
同上,reverse 也是鸭式辨型的受益者,颠倒元素的范围受length属性制约。如下:
如果 length 属性小于1 或者 length 属性不为数值,那么原类数组对象将没有变化。即使 length 属性不存在,该对象也不会去创建 length 属性。特别的是,当 length 属性较大时,类数组对象的『索引』会尽可能的向 length 看齐。
三、队列方法:
就像栈是以LIFO形式限制访问的数据结构一样,队列以先进先出(FIFO,First-In-First-Out)形式限制访问。队列在列表末尾添加数据,但从列表开头获取数据。因为有了在数据末尾添加数据的push()方法,所以要模拟队列就差一个从数组开头取得数据的方法了。这个数组方法叫shift(),它会删除数组的第一项并返回它,然后数组长度减1。使用shift()和push(),可以把数组当成队列来使用:
1、shift
shift()方法删除数组的第一个元素,长度会减1,并返回这个元素。类似于队列的队尾弹出最后一个元素。
(1) 语法:arr.shift()
(2) 同样受益于鸭式辨型,对于类数组对象,shift仍然能够处理。如下:
(3)如果类数组对象length属性不存在,将添加length属性,并初始化为0.如下:
2、push
在队列最后插进一个新元素,与进栈的push()用法一致。
四、操作方法:
1、splice
splice()方法用新元素替换旧元素的方式来修改数组。它是一个常用的方法,复杂的数组操作场景通常都会有它的身影,特别是需要维持原数组引用时,就地删除或者新增元素,splice是最适合的。
(1)语法: arr.splice(start, deleteCount [, item1[, item2[, …]]])
start: 指定从哪一位开始修改内容。如果超过了数组长度,则从数组末尾开始添加内容;如果是负值,则其指定的索引位置等同于 length+start (length为数组的长度),表示从数组末尾开始的第 -start 位。
deleteCount: 指定要删除的元素个数,若等于0,则不删除。这种情况下,至少应该添加一位新元素,若大于start之后的元素总和,则start及之后的元素都将被删除。
itemN: 指定新增的元素,如果缺省,则该方法只删除数组元素。
返回值: 由原数组中被删除元素组成的数组,如果没有删除,则返回一个空数组。
❑ 删除。需要给splice()传2个参数:要删除的第一个元素的位置和要删除的元素数量。可以从数组中删除任意多个元素,比如splice(0, 2)会删除前两个元素。
❑ 插入。需要给splice()传3个参数:开始位置、0(要删除的元素数量)和要插入的元素,可以在数组中指定的位置插入元素。第三个参数之后还可以传第四个、第五个参数,乃至任意多个要插入的元素。比如,splice(2, 0,"red", "green")会从数组位置2开始插入字符串"red"和"green"。
❑ 替换。splice()在删除元素的同时可以在指定位置插入新元素,同样要传入3个参数:开始位置、要删除元素的数量和要插入的任意多个元素。要插入的元素数量不一定跟删除的元素数量一致。比如,splice(2, 1, "red","green")会在位置2删除一个元素,然后从该位置开始向数组中插入"red"和"green"。
splice()方法始终返回这样一个数组,它包含从数组中被删除的元素(如果没有删除元素,则返回空数组)。
如下例子:
// 删除
var array = ["apple","boy"];
var splices = array.splice(1,1);
console.log(array); // ["apple"]
console.log(splices); // ["boy"] ,可见是从数组下标为1的元素开始删除,并且删除一个元素,由于itemN缺省,故此时该方法只删除元素
// 新增
array = ["apple","boy"];
splices = array.splice(2,1,"cat");
console.log(array); // ["apple", "boy", "cat"]
console.log(splices); // [], 可见由于start超过数组长度,此时从数组末尾开始添加元素,并且原数组不会发生删除行为
//替换
array = ["apple","boy"];
splices = array.splice(-2,1,"cat");
console.log(array); // ["cat", "boy"]
console.log(splices); // ["apple"], 可见当start为负值时,是从数组末尾开始的第-start位开始删除,删除一个元素,并且从此处插入了一个元素
array = ["apple","boy"];
splices = array.splice(-3,1,"cat");
console.log(array); // ["cat", "boy"]
console.log(splices); // ["apple"], 可见即使-start超出数组长度,数组默认从首位开始删除
array = ["apple","boy"];
splices = array.splice(0,3,"cat");
console.log(array); // ["cat"]
console.log(splices); // ["apple", "boy"], 可见当deleteCount大于数组start之后的元素总和时,start及之后的元素都将被删除
(2)同上,splice一样受益于鸭式辨型,
由此可见,对象o删除了一个属性,并且length-1,并且返回的依旧是被删除的属性。
(3)如果需要删除数组中一个已经存在的元素,可参考如下:
var array = ['a', 'b', 'c'];
array.splice(array.indexOf('b'), 1);
2、unshift
unshift() 方法:顾名思义,unshift()就是执行跟shift()相反的操作:在数组开头添加任意多个值,然后返回新的数组长度。通过使用unshift()和pop(),可以在相反方向上模拟队列,即在数组开头添加新数据,在数组末尾取得数据。
(1)语法:arr.unshift(element1, …, elementN)
length为5说明,这两个属性成功的插入到数组中了。是队列的头部插进的。
(2)如果传进去的是一个数组,则:
(3)unshift也受益于鸭式辨型,例子如下:
注意:如果类数组对象不指定length属性,则会返回{0: 'gray', 1: 'green', 2: 'blue', length: 1},unshift会认为数组长度为0,此时将从对象下标为0的位置开始插入,相应位置属性将被替换,此时初始化类数组对象的length属性为插入元素个数。
var o2 = {0:"red", 1:"green", 2:"blue"};
var length = Array.prototype.unshift.call(o2,"gray", "orange", "black");
varo2 = {0:"red", 1:"green", 2:"blue"};
var length = Array.prototype.unshift.call(o2,"gray", "orange", "black");
如果插进去的属性个数多了,好像原来的数据就会消失????
五、复制和填充的方法:
ES6新增了两个方法:批量复制方法copyWithin(),以及填充数组方法fill()
1、copyWithin
copyWithin() 方法基于ECMAScript 2015(ES6)规范,用于数组内元素之间的替换,即替换元素和被替换元素均是数组内的元素。
(1)语法:arr.copyWithin(target, start[, end = this.length])
target: 开始插入的位置的索引(下标是从0开始数)【必选】;
start:要开始复制的那个元素的索引;
end:要结束复制元素的索引。
返回值就是复制后的新数组。
// start~end 的复制元素索引包括start索引的位置,不包括end索引的位置
var arr=[1,2,3,4,5,6];
arr.copyWithin(1,2,3); // 复制索引2~3位置上的元素,其实就是复制索引2位置的元素3,插入到索引为1的位置。
结果如下:
// 如果只有一个参数,即该参数为插入的位置的索引,那就是默认从索引0开始复制到之后一个
var array=[1,2,3,4,5];
array.copyWithin(2); // 复制从索引0开始的所有元素,从索引2的位置开始按顺序插入,
结果如下:
// 如果有两个参数,第一个参数为插入位置的索引,第二个参数为开始复制位置的索引
var array=[1,2,3,4,5];
array.copyWithin(1,3); // 复制从索引3开始以及后面的元素,插入到索引为1的位置以及后面j结果日下
结果如下:
// 如果参数为负数,则从最后一个元素倒着数,或者加上原来数组的长度,然后按照正数的规则来计算
array=[1,2,3,4,5];
array.copyWithin(-1,-3);// 复制从索引为(-3+5)2的位置开始以及后面的元素插入到索引为(-1+5)4的位置。
结果如下:
(2)同上,copyWithin一样受益于鸭式辨型,例如:
注意:如果类数组对象不指定length属性,copyWithin会认为数组的长度为undefined。
2、fill
fill()同样用于数组元素替换,但与copyWithin略有不同,它主要用于将数组指定区间内的元素替换为某个值。
(1)语法:arr.fill(value, start[, end = this.length])
value:是要替换为的元素值,start是开始位置的索引,end是结束位置的索引
【注意】start~end之间的包括索引start,不包括索引end
(2)用法与copyWithin()基本一样。例子如下:
(3)同上,fill 一样受益于鸭式辨型,例如:
注意:如果类数组对象不指定length属性,copyWithin会认为数组的长度为undefined。