JavaScript中的数组
参考书籍:《JavaScript高级程序设计(第3版)》
作为一种可以说是最常用的类型,EMCAScript
当中的数组与其他语言的数组有很大区别,例如数组元素可以是不同类型,数组长度可以动态调整等,因此我总结了一下EMCAScript
中的数组类型,即 $Array$ 类型(主要集中于与其他语言不同的地方)。
1. 数组创建
EMCAScript
中数组是一个特殊的类型,有自己的构造函数,我们可以通过 $new$ 运算符来调用数组的构造函数。
var array = new Array(); //建立一个空数组
当然,你也可以通过传参来调用带参构造函数。
var array1 = new Array(10); //大小为10的数组
var array2 = new Array(1, 2, 3); //包含1,2,3三个元素的数组
var array2 = new Array("A"); //包含一个"A"的数组
但是在这里要注意的是,如果你只给构造函数传一个数字,则会创建对应大小的数组,其中每一项的值都是 $undefined$ ;如果传的是多个数字,则会创建包含这些数字的数组。
除了调用构造函数之外,我们还可以使用字面量语法。如下所示:
var array1 = []; //空数组
var array2 = [1]; //包含一个1的数组
var array3 = ["A", "B", "C"]; //包含三个元素的数组
2. 数组长度
与其他语言相似,EMCAScript
中的数组下标从 $0$ 开始, $length - 1$ 结束,要访问对应下标的值,可以通过方括号内添加下标读取或者写入数据,如下所示:
var array = ["A", "B", "C"];
console.log(array[0]); // "A"
array[0] = "D";
console.log(array[0]); // "D"
但是与其他语言不同的是,如果你访问的下标超过了当前数组的长度,即 $length - 1$ ,会返回 $undefined$。而你在这时写入数据的话,数组的长度会更新为你访问的下标值加一,而从原先的最大下标到新的最大下标之间的值会以 $undefined$ 填充。如下所示:
var array = ["A", "B", "C"];
console.log(array[5]); //undefined
array[5] = "F";
console.log(array[4]); //undefined
console.log(array[5]); //"F"
EMCAScript
中的数组长度还有个特点,就是它不是只读的,你可以通过设置数组长度的值直接改变数组大小,这时新增的值会以 $undefined$ 填充。如下所示:
var array = ["A", "B", "C"];
array.length = 2;
console.log(array[2]); //undefined
array.length = 4;
console.log(array[2]); //undefined
3. 数组方法
EMCAScript
中的数组方法非常有特点,它使得JavaScript
中的数组可以代替多种结构。
3.1 判定方法
由于JavaScript
是一门弱类型语言,因此如何判断一个对象为数组非常有用的,对于一个网页或者全局作用域,使用 $instanceof$ 操作符即可。如下所示:
var array = [];
console.log(array instanceof Array); //true
但问题在于,如果存在多个框架,即多个全局作用域,这时如果你从另一个框架传入数组,由于各个框架中的数组分别有各自的构造函数,因此这时对另一个框架中的数组使用 $instanceof$ 操作符时会返回 $false$ 。
为了避免这种情况,可以使用EMCAScript5
中的 $Array.isArray(\ )$ 方法,该方法不会受到作用域影响,如下所示:
var array = [];
console.log(Array.isArray(array)); //true
当然要注意的是,可能有的浏览器不支持该方法。
3.2 转换方法
EMCAScript
中所有的对象都具有三个方法—— $toLocaleString(\ )$ 、$toString(\ )$ 以及 $valueOf(\ )$ 方法。其中 $valueOf(\ )$ 方法返回数组本身;$toString(\ )$ 方法以字符串的形式返回数组中的所有元素(每个元素之间用逗号隔开);$toLocaleString(\ )$ 大部分情况下与 $toString(\ )$ 返回相同的值,但是不同之处在于 $toLocaleString(\ )$ 方法是调用每个元素的 $toLocaleString(\ )$ 方法后再用逗号连接起来,也就是说当一个元素的 $toString(\ )$ 方法与它的 $toLocaleString(\ )$ 方法不同时,调用数组的 $toString(\ )$ 方法和 $toLocaleString(\ )$ 方法就会返回不同的值。
var object = {
toLocaleString: function() {
return "LocaleString";
},
toString: function() {
return "String";
}
};
var array = [1, object];
console.log(array.toString()); //"1,String"
console.log(array.toLocaleString()); //"1,LocaleString"
3.3 栈方法
通过EMCAScript
中数组的栈方法,我们可以把一个数组当成栈来使用。实现栈的两个方法分别是 $Array.prototype.push(\ )$ 和 $Array.prototype.pop(\ )$ 。$Array.prototype.push(\ )$ 方法接收一个或多个参数,将这些参数按序压入栈内,返回参数个数;$Array.prototype.pop(\ )$ 方法推出栈顶元素并返回。
var stack = [];
console.log(stack.push(1, 2)); // 2
console.log(stack.pop()); // 2
console.log(stack.length); // 1
3.4 队列方法
类似于栈方法,EMCAScript
中也提供了能够让一个数组当作队列使用的方法。由于 $Array.prototype.push(\ )$ 方法本身就是向末尾添加元素的方法,因此只需要另一个从数组开始删除元素的方法即可,实现这一操作的方法就是 $Array.prototype.shift(\ )$ 方法,它能够删除并返回数组第一项元素。此外,EMCAScript
还提供了一 $Array.prototype.unshift(\ )$ ,即向数组开始添加元素并返回元素个数。通过结合 $Array.prototype.push(\ )$ , $Array.prototype.pop(\ )$ , $Array.prototype.shift(\ )$ , $Array.prototype.unshift(\ )$ 这四个方法,我们能够把一个数组当作双向队列使用。
var array = [];
console.log(array.unshift(3, 2)); // 2
console.log(array.shift()); // 3
3.5 排序方法
EMCAScript
中提供了两个数组排序方法—— $Array.prototype.reverse(\ )$ 和 $Array.prototype.sort(\ )$ ,分别用于数组反转和排序。需要注意的是,在不传参数的情况下 $Array.prototype.sort(\ )$ 方法默认会调用每个元素的 $toString(\ )$ 方法,之后通过字符串比较来确定大小,得到升序数组。而通过传参,我们可以得到想要的排序数组,具体的传入参数应该是一个函数对象,类似于C++
和Java
中的排序方法,该函数接收两个元素,若前者需要排在后者前面,则应返回一个负数,若前者等于后者,则返回 $0$ ,若前者需要排在后者后面,则返回一个正数。如下所示:
var array = [1, 3, 4, 5, 6];
array.sort(function(value1, value2) {
return value2 - value1;
});
console.log(array); // "6,5,4,3,1"
3.6 操作方法
EMCAScript
提供了很多操作方法,这里选择了几个常用方法。
- $Array.prototype.concat(\ )$ 方法
- 用于连接两个数组,或者将一个元素添加到数组末尾,若未传入参数,返回数组本身。
- $Array.prototype.slice(\ )$ 方法
- 当接收一个参数时,该参数指定一个位置,返回一个新数组,元素为之前数组的指定位置到末尾的所有元素
- 当接收两个参数时,第一个参数指定位置,第二个参数指定结束位置,返回一个新数组,元素为之前数组指定的起始位置到指定的结束位置之间的所有元素。
- $Array.prototype.splice(\ )$ 方法
- 当接收两个参数时,第一个参数指定位置,第二个参数指定个数,删除数组中从起始位置开始对应个数的元素,并返回一个储存这些元素的数组
- 当接收三个或多个参数时,第一个参数指定起始位置,第二个参数指定个数,之后的参数为要插入的元素,删除数组中从指定位置开始对应个数的元素,再插入指定的元素。
var array = [1, 2, 3];
console.log(array.concat([4, 5], 6, 7)); // "1,2,3,4,5,6,7"
console.log(array.slice(1, 2)); // "2"
console.log(array.splice(1, 2, 3, 4, 5)); // "2,3"
console.log(array); // "1,3,4,5"
3.7 位置方法
类似于Java
,EMCAScript
提供了 $Array.indexOf(\ )$ 方法和 $Array.lastIndexOf(\ )$ 。且其用法也与Java
相似,传入要查找的元素,返回其位置,若未找到,返回 $-1$ 。
console.log([1, 2, 3].lastIndexOf(2)); // 1
3.8 迭代方法
迭代方法,即遍历数组,对每个元素执行某个指定操作的函数。EMCAScript
中提供了五个迭代方法,每个方法都接收一个或两个参数,第一个参数指定要进行操作的函数,第二个参数(可选)指定前者运行的作用域。传入的函数接收三个参数,数组元素的值、位置和数组本身。迭代方法会遍历数组,并对其中的每个元素执行指定的函数。这些迭代方法的返回值可能会受到传入的函数的影响,返回值的主要区别是:
- $every(\ )$ :只有所有元素的返回值均为 $true$ 时,返回 $true$ 。
- $filter(\ )$ :返回一个由数组中返回 $true$ 的元素组成的数组。
- $forEach(\ )$ :无返回值。
- $map(\ )$ :返回一个储存每次函数调用结果的数组。
- $some(\ )$ :若数组中有任何一个元素返回 $true$ ,返回 $true$ 。
以 $filter(\ )$ 为例,我们可以这样使用迭代方法:
console.log([1, 2, 3, 4].filter(function(value, index, array) {
return value > 2;
})); // "3,4"
3.9 归并方法
归并方法用于归并数组,接收两个参数,第一个为对每个元素执行的函数,第二个参数(可选)为归并初始值。指定的函数接收四个参数——前一个元素的值,当前元素的值、位置和数组本身,返回值作为第一个参数传入下次调用。如果没有提供第二个参数,归并方法的第一次迭代将发生在数组第二项元素,第一项元素为初始值。EMCAScript
提供了两个归并方法—— $reduce(\ )$ 和 $reduceRight(\ )$ ,前者正序遍历,后者逆序遍历。使用归并方法求和的程序为:
console.log([1, 2, 3].reduce(function(pre, cur, index, array) {
return pre + cur;
})); // 6