6.2.1 创建数组
创建数组的方法:
一种是使用Array构造函数
比如:
let colors = new Array();
如果知道数组中元素的数量,那么可以给构造函数传入一个数值,然后length属性就会被自动创建并设置为这个值。比如,下面的代码会创建一个初始length为20的数组:
let colors = new Array(20);
也可以给Array构造函数传入要保存的元素。
比如,下面的代码会创建一个包含3个字符串值的数组:
let colors = new Array('red', 'blue', 'green');
创建数组时可以给构造函数传一个值。这时候就有点问题了,因为如果这个值是数值,则会创建一个长度为指定数值的数组;而如果这个值是其他类型的,则会创建一个只包含该特定值的数组。
另一种创建数组的方式是使用数组字面量(array literal)表示法。
数组字面量是在中括号中包含以逗号分隔的元素列表
如下面的例子所示:
let colors = ['red', 'blue', 'green']; //创建一个包含3个元素的数组let names = []; // 创建一个空数组let values = [1,2,]; // 创建一个包含2个元素的数组
ES6新增的用于创建数组的静态方法:from()和of()
from()用于将类数组结构转换为数组实例
of()用于将一组参数转换为数组实例
Array.from()的第一个参数是一个类数组对象,即任何可迭代的结构,或者有一个length属性和可索引元素的结构。这种方式可用于很多场合:

Array.from()还接收第二个可选的映射函数参数。这个函数可以直接增强新数组的值,而无须像调用Array.from().map()那样先创建一个中间数组。
还可以接收第三个可选参数,用于指定映射函数中this的值。但这个重写的this值在箭头函数中不适用。
Array.of()可以把一组参数转换为数组。
这个方法用于替代在ES6之前常用的Array.prototype.slice.call(arguments),一种异常笨拙的将arguments对象转换为数组的写法:
6.2.2 数组空位
使用数组字面量初始化数组时,可以使用一串逗号来创建空位(hole)。ECMAScript会将逗号之间相应索引位置的值当成空位,ES6规范重新定义了该如何处理这些空位。
ES6新增的方法和迭代器与早期ECMAScript版本中存在的方法行为不同。ES6新增方法普遍将这些空位当成存在的元素,只不过值为undefined
注:由于行为不一致和存在性能隐患,因此实践中要避免使用数组空位。如果确实需要空位,则可以显式地用undefined值代替。
6.2.3 数组索引
要取得或设置数组的值,需要使用中括号并提供相应值的数字索引
数组length属性的独特之处在于,它不是只读的。通过修改length属性,可以从数组末尾删除或添加元素。
注:数组最多可以包含4294967295个元素,这对于大多数编程任务应该足够了。如果尝试添加更多项,则会导致抛出错误。以这个最大值作为初始值创建数组,可能导致脚本运行时间过长的错误。
6.2.4 检测数组
instanceof操作符
Array.isArray()方法
这个方法的目的就是确定一个值是否为数组,而不用管它是在哪个全局执行上下文中创建的
6.2.5 迭代器方法
在ES6中,Array的原型上暴露了3个用于检索数组内容的方法:keys()、values()和entries()
keys()返回数组索引的迭代器
values()返回数组元素的迭代器
entries()返回索引/值对的迭代器
使用ES6的解构可以非常容易地在循环中拆分键/值对:
6.2.6 复制和填充方法
ES6新增了两个方法:批量复制方法copyWithin(),以及填充数组方法fill()。
这两个方法的函数签名类似,都需要指定既有数组实例上的一个范围,包含开始索引,不包含结束索引。
使用这个方法不会改变数组的大小。
使用fill()方法可以向一个已有的数组中插入全部或部分相同的值。
开始索引用于指定开始填充的位置,它是可选的。如果不提供结束索引,则一直填充到数组末尾。
负值索引从数组末尾开始计算。也可以将负索引想象成数组长度加上它得到的一个正索引
fill()静默忽略超出数组边界、零长度及方向相反的索引范围:
与fill()不同,copyWithin()会按照指定范围浅复制数组中的部分内容,然后将它们插入到指定索引开始的位置。开始索引和结束索引则与fill()使用同样的计算方法
copyWithin()静默忽略超出数组边界、零长度及方向相反的索引范围:
6.2.7 转换方法
所有对象都有toLocaleString()、toString()和valueOf()方法
valueOf()返回的还是数组本身
toString()返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串。也就是说,对数组的每个值都会调用其toString()方法,以得到最终的字符串
6.2.8 栈方法
ECMAScript给数组提供几个方法,让它看起来像是另外一种数据结构。
数组对象可以像栈一样,也就是一种限制插入和删除项的数据结构。
栈是一种后进先出(LIFO, Last-In-First-Out)的结构,也就是最近添加的项先被删除。
数据项的插入(称为推入,push)和删除(称为弹出,pop)只在栈的一个地方发生,即栈顶。
ECMAScript数组提供了push()和pop()方法,以实现类似栈的行为。
push()方法接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度。
pop()方法则用于删除数组的最后一项,同时减少数组的length值,返回被删除的项。
6.2.9 队列方法
就像栈是以LIFO形式限制访问的数据结构一样,队列以先进先出(FIFO, First-In-First-Out)形式限制访问。
队列在列表末尾添加数据,但从列表开头获取数据。
在数据末尾添加数据的push()方法,要模拟队列就差一个从数组开头取得数据的方法。这个数组方法叫shift(),它会删除数组的第一项并返回它,然后数组长度减1。
使用shift()和push(),可以把数组当成队列来使用
ECMAScript也为数组提供了unshift()方法。执行跟shift()相反的操作:在数组开头添加任意多个值,然后返回新的数组长度。
通过使用unshift()和pop(),可以在相反方向上模拟队列,即在数组开头添加新数据,在数组末尾取得数据
6.2.10 排序方法
数组有两个方法可以用来对元素重新排序:reverse()和sort()
reverse()方法就是将数组元素反向排列
默认情况下,sort()会按照升序重新排列数组元素,即最小的值在前面,最大的值在后面。
为此,sort()会在每一项上调用String()转型函数,然后比较字符串来决定顺序。
即使数组的元素都是数值,也会先把数组转换为字符串再比较、排序
一开始数组中数值的顺序是正确的,但调用sort()会按照这些数值的字符串形式重新排序。
因此,即使5小于10,但字符串”10”在字符串”5”的前头,所以10还是会排到5前面。很明显,这在多数情况下都不是最合适的。
为此,sort()方法可以接收一个比较函数,用于判断哪个值应该排在前面
比较函数接收两个参数,
如果第一个参数应该排在第二个参数前面,就返回负值;
如果两个参数相等,就返回0;
如果第一个参数应该排在第二个参数后面,就返回正值
比较函数也可以产生降序效果,只要把返回值交换一下
可简写为一个箭头函数:
注:reverse()和sort()都返回调用它们的数组的引用。
如果数组的元素是数值,或者是其valueOf()方法返回数值的对象(如Date对象),这个比较函数还可以写得更简单,因为这时可以直接用第二个值减去第一个值:
比较函数就是要返回小于0、0和大于0的数值,因此减法操作完全可以满足要求。
6.2.11 操作方法
对于数组中的元素,有很多操作方法。
concat()方法可以在现有数组全部元素基础上创建一个新数组。
它首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组。
如果传入一个或多个数组,则concat()会把这些数组的每一项都添加到结果数组。
如果参数不是数组,则直接把它们添加到结果数组末尾。
方法slice()用于创建一个包含原有数组中一个或多个元素的新数组。
slice()方法可以接收一个或两个参数:返回元素的开始索引和结束索引。
如果只有一个参数,则slice()会返回该索引到数组末尾的所有元素。
如果有两个参数,则slice()返回从开始索引到结束索引对应的所有元素,其中不包含结束索引对应的元素。
记住,这个操作不影响原始数组
注:如果slice()的参数有负值,那么就以数值长度加上这个负值的结果确定位置。
比如,在包含5个元素的数组上调用slice(-2, -1),就相当于调用slice(3,4)。如果结束位置小于开始位置,则返回空数组。
最强大的数组方法就属splice()了,使用它的方式可以有很多种。
splice()的主要目的是在数组中间插入元素,但有3种不同的方式使用这个方法:
❑ 删除。需要给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()方法始终返回这样一个数组,它包含从数组中被删除的元素(如果没有删除元素,则返回空数组)
6.2.12 搜索和位置方法
ECMAScript提供两类搜索数组的方法:按严格相等搜索和按断言函数搜索。
1.严格相等
ECMAScript提供了3个严格相等的搜索方法:indexOf()、lastIndexOf()和includes()
前两个方法在所有版本中都可用,而第三个方法是ECMAScript 7新增的。
这些方法都接收两个参数:要查找的元素和一个可选的起始搜索位置。
indexOf()和includes()方法从数组前头(第一项)开始向后搜索,而lastIndexOf()从数组末尾(最后一项)开始向前搜索。
indexOf()和lastIndexOf()都返回要查找的元素在数组中的位置,如果没找到则返回-1。
includes()返回布尔值,表示是否至少找到一个与指定元素匹配的项。
在比较第一个参数跟数组每一项时,会使用全等(===)比较,也就是说两项必须严格相等
2.断言函数
ECMAScript也允许按照定义的断言函数搜索数组,每个索引都会调用这个函数。断言函数的返回值决定了相应索引的元素是否被认为匹配。
断言函数接收3个参数:元素、索引和数组本身。
元素是数组中当前搜索的元素,索引是当前元素的索引,而数组就是正在搜索的数组。
断言函数返回真值,表示是否匹配。
find()和findIndex()方法使用了断言函数。
这两个方法都从数组的最小索引开始。
find()返回第一个匹配的元素,findIndex()返回第一个匹配元素的索引。这两个方法也都接收第二个可选的参数,用于指定断言函数内部this的值。
找到匹配项后,这两个方法都不再继续搜索。
6.2.13 迭代方法
ECMAScript为数组定义了5个迭代方法。
每个方法接收两个参数:以每一项为参数运行的函数,以及可选的作为函数运行上下文的作用域对象(影响函数中this的值)。传给每个方法的函数接收3个参数:数组元素、元素索引和数组本身。
因具体方法而异,这个函数的执行结果可能会也可能不会影响方法的返回值。
数组的5个迭代方法如下:
❑ every():对数组每一项都运行传入的函数,如果对每一项函数都返回true,则这个方法返回true。
❑ filter():对数组每一项都运行传入的函数,函数返回true的项会组成数组之后返回。
❑ forEach():对数组每一项都运行传入的函数,没有返回值。
❑ map():对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组。
❑ some():对数组每一项都运行传入的函数,如果有一项函数返回true,则这个方法返回true。
这些方法都不改变调用它们的数组。
看一看filter()方法。这个方法基于给定的函数来决定某一项是否应该包含在它返回的数组中。
比如,要返回一个所有数值都大于2的数组,可以使用如下代码:
map()方法也会返回一个数组。这个数组的每一项都是对原始数组中同样位置的元素运行传入函数而返回的结果。
例如,可以将一个数组中的每一项都乘以2,并返回包含所有结果的数组,如下所示:
以上代码返回了一个数组,包含原始数组中每个值乘以2的结果。这个方法非常适合创建一个与原始数组元素一一对应的新数组。
再来看forEach()方法。这个方法只会对每一项运行传入的函数,没有返回值。本质上,forEach()方法相当于使用for循环遍历数组。
比如:
6.2.14 归并方法
ECMAScript为数组提供了两个归并方法:reduce()和reduceRight()
这两个方法都会迭代数组的所有项,并在此基础上构建一个最终返回值
reduce()方法从数组第一项开始遍历到最后一项,reduceRight()从最后一项开始遍历至第一项。
这两个方法都接收两个参数:对每一项都会运行的归并函数,以及可选的以之为归并起点的初始值。
传给reduce()和reduceRight()的函数接收4个参数:上一个归并值、当前项、当前项的索引和数组本身。
这个函数返回的任何值都会作为下一次调用同一个函数的第一个参数。
如果没有给这两个方法传入可选的第二个参数(作为归并起点值),则第一次迭代将从数组的第二项开始,因此传给归并函数的第一个参数是数组的第一项,第二个参数是数组的第二项
