红宝书用了17页来讲Array这一个类型,足以说明它的重要性。
虽然我们都知道Array本意是数组,不过JS里的Array有点特殊:它的每一项都是可以保存任何类型的数据;而且,数组的大小可以动态调整(随着数据的添加自动增长以容纳新数据)
创建:
创建数组的基本方式有两种:
1.使用new操作符(可以省略)后跟Array构造函数:
var colors = new Array(); //括号内可以传入数字,表示数组长度;传入字符串,表示元素
var names = Array("Greg") //省略new操作符,并且第一个数组远赴赋值为Greg
2.数组字面量:由一对包含数组项的方括号表示(这个方法就很C/C++/Python……我的意思是之前学那些的时候我都这么创建数组的),多个数组项之间用逗号隔开;
读取/获取:
读取和设置数组的时候,索引要基于0(这个应该学过编程语言的大家都知道的吧)
特殊用法:删除/添加新项——利用length属性:
var colors = ["red", "blue", "green"]; //创建一个长度为3,包含3个字符串的数组
colors.length = 2; //将数组长度设置为2(减少了colors数组的长度)
alert(colors[2]); //提示undefined,索引位置2的元素被删除了(因为现在colors数组元素没有那么长)
var names = ["Jack", "Mike", "Ryan"];
names.length = 4; //将数组长度设置为4(增加了names数组的长度)
alert(names[3]); //提示undefined,这个是因为索引位置3上的元素没有赋值
※数组的最后一项的索引始终是length-1※
检测数组:
①instanceof:
if (value instanceof Array) {
//The operation on the array
}
这个方法用于一个网页,或者一个全局作用域内;
问题在于它假定只有一个全局执行环境。若网页中包含多个框架,那么全局执行环境就不止一个,Array构造函数也不止一个。此时从一个框架向另一个框架传入一个数组,则这两个数组(被传入的,和目标框架中原生创建的)分别具有各自不同的构造函数。
②Array.isArray():
这个方法用于解决方法①的问题。这个方法的目的是最终确定某个值到底是不是数组:
if (Array.isArray(value)) {
//The operation on the array
}
转换方法:
所有对象都具有toLocaleString(),toString(),valueOf()方法。valueOf()返回的是数组本身;toString()返回由数组中每个值的字符串形式拼接而成的一个,以逗号分隔的字符串。
BTW:数组中某一相值是null或者undefined,该值在转换后返回的结果中呈现形式为空字符串。
栈:
又看到了一个熟悉的字眼。栈这个东西的最大特点就是LIFO(Last In First Out)——最新添加的项最早被移除。
插入项的方法为push();移除项的方法为pop();数组也支持这两项方法。
队列:
依然是个熟悉的字眼,特点是FIFO(First In First Out)——队列在列表末段添加项,在列表前端移除项,实现方法为shift()
shift()能够移除队列中的第一个项,并返回该项,同时将数组长度-1。搭配shift()与push()可以将数组像队列一般操作;
同时数组还支持unshift()方法,在数组前段添加任意个项,并返回新数组的长度。用unshift()与pop()可以反向模拟队列;
重排序方法:
以下两种方法的返回值都是经过排序后的数组:
①reverse(),用以反转数组项的顺序;
②sort(),用以通过比较数组的字符串值来升序排序;
sort()方法的灵活使用——接收比较函数(自己写)作为参数:
function compare(value1, value2) { //将compare()作为比较函数,升序
if (value1 > value2) {
return 1;
} else if (value1 < value2) {
return -1;
} else {
return 0;
}
}
var values = [0, 10, 15, 1, 5];
values.sort(compare);
alert(values); //0, 1, 5, 10, 15
对于数值类型,或者是其valueOf()会返回数值类型的对象,可以用更简单的比较函数:return value2 - value1;
操作方法:
这一部分的对数组的多种操作,(在算法的设计实现上)实用性很强。如果大家买过《算法图解》这本书并访问过其GitHub页面《Grokking Algorithms》一书的代码实现汇总 查看各个算法的JS实现方式,就会发现有很多算法的处理都用到了这一部分。
①concat():连接数组——基于当前数组中的所有项创建一个新数组。
具体实现:创建当前数组的一个副本,然后将接收到的参数添加到这个副本的末位,最后返回新构建的数组。
②slice():找出选定元素——既与当前数组中的一个或多个项创建一个新数组。
具体实现:slice()函数接收一或两个参数,即要返回项的起始位置(必填)与结束位置(可选,不选的话直接到数组末尾)。
※slice()的第一个参数为数组的索引位,第二个参数为次序位(索引位+1)※
※参数为负数:数组长度加上该参数来获得相应的位置;结束位小于起始位,返回空数组※
③splice():插入||删除||替换
主要用途是向数组的中部插入项,但具体可转化为上述三种:
删除:删除任意数量的项。指定两个参数:要删除的第一项的索引位、要删除的项的个数(如splice(0, 2)将删除前两个项);
插入:向指定位置插入任意数量的项。提供至少三个参数:起始位置、0、要插入的(一/多个)项(如splice(2, 0, "red", "green")会从当前数组的索引位置2开始,插入两个字符串——red与green);
替换:向指定位置插入任意数量的项,并同时删除任意数量的项。提供至少三个参数:起始位置、要删除的项的个数、要插入的(一/多个)项(如splice(2, 1, "red", "green")会从当前数组的索引位置2开始,删除一个项(此处为索引位置2对应的项),再从位置2的前面按照传入顺序插入两个字符串——red与green)
※splice()始终返回一个数组,该方法中包含从原始数组中删除的项,该方法会对原始数组进行调整※
位置方法:
介绍两个查找位置的方法indexOf()、lastIndexOf();
这两个方法都接收两个参数:要查找的项(必选)与表示查找起点位置的索引(可选);
这两个方法都返回要查找的项在数组中的位置,或者在没找到的情况下返回-1;
在比较第一个参数与数组的每一项时,使用全等操作符(严格相等===)
①indexOf():从数组开头(索引位置0)开始数,直到起点位置,并开始向后查找,并返回这个元素从前向后数的所在位置。
②lastIndexOf():从数组末尾开始数,直到起点位置,并开始向前查找,并返回从后向前找所找到的那个元素的位置(这个位置是从前向后排的)。
迭代方法:
数组具有五个迭代方法,每个方法都接受两个参数:要在每一项上运行的函数(必选),运行该函数的作用域对象(可选)——影响this的值。传入这些方法中的函数会接受三个参数:数组项的值、该项在数组中的位置、数组对象本身。
①every():对数组中的每一项运行给定函数,若该函数对每一项都返回true,这个方法才返回true,否则返回false;
②some():对数组中的每一项运行给定函数,若该函数对任一项返回true,则返回true,否则返回false;
③filter():对数组中的每一项运行给定函数,返回该函数会返回true的项所组成的数组;
④forEach():对数组中的每一项运行给定函数,没有返回值;
⑤map():对数组中的每一项运行给定函数,返回每次函数调用的结果所组成的数组;
※以上方法都不会修改数组中包含的值※
归并方法:
两个归并数组的方法——迭代数组的所有项,然后构建一个最终返回值
这两个方法都接受两个参数:一个在每一项上调用的函数(必选),作为归并基础的初始值(可选);传给这两个方法的函数,接收四个参数:前一个值、当前值、项的索引、数组对象。这个函数返回的任何值都会作为第一个参数自动传递给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数是数组的第二项。
①reduce():从数组的第一项开始逐个遍历到最后;
②reduceRight():从数组的最后一项开始,向前遍历到第一项;