原文地址:https://wangdoc.com/javascript/
定义
任何类型的数据都可以放入数组。
var arr = [
{a : 1},
[1, 2, 3],
function() { return true; }
];
上面数组的三个成员分别是对象、数组、函数。
数组的本质
本质上,数组是一种特殊的对象。typeof运算符会返回数组的类型object。
数组的特殊性体现在,它的键名是按次序排列的一组整数。
var arr = ["a", "b", "c"];
Object.keys(arr); // ["0", "1", "2"]
前面提过,JavaScript语言规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串。之所以可以用数值读取,是因为做了类型的转换。这种情况在赋值中也成立。
var a = [];
a[1.00] = 6;
a[1] // 6
取数组中的值,只能通过方括号运算符,因为方括号运算符可以接受数值。
length属性
JavaScript使用一个32位整数保存数组的元素个数。这意味着,数组成员最多只有(2^32 - 1)个。只要是数组,就一定有length属性。该属性是一个动态的值,等于键名中的最大整数加上1。
数组的数字键不需要连续,length属性总是比最大的那个整数大1。
var arr = ["a", "b"];
arr.length // 2
arr[3] = "c";
arr.length // 3
arr[9] = "d";
arr.length // 10
a[8] // undefined
length属性是可写的,如果人为设置一个小于当前成员个数,该数组会减少到length设置的值。
清空数组的一个有效办法就是将length设置为0。人为设置length为非法值,会出现RangeError的错误。
值得注意的是,**由于数组本质上是一种对象,所以可以为数组添加属性,但是这不影响length属性的值。
var a = [];
a["p"] = "abc";
a.length // 0
a[2.1] = "abc";
a.length // 0
in运算符
检查某个键名是否存在的运算符in,适用于对象,也适用于数组。
var arr = ["a", "b", "c"];
2 in arr // true
"2" in arr // true
4 in arr // false
注意,如果数组的某个位置是空位,in运算符返回false。
var arr = [];
arr[100] = "a";
100 in arr // true
1 in arr // false
上面代码中,数组arr只有一个成员arr[100],其他位置的键名都会返回false。
for...in循环和数组的遍历
for...in循环不仅可以遍历对象,也可以遍历数组。
var a = [1, 2, 3];
for (var i in a) {
// ...
}
但是,for...in循环不仅遍历数组所有的数字键,还会遍历非数字键。
var a = [1, 2, 3];
a.foo = true;
for (var key in a) {
console.log(key)
}
// 0 1 2 foo
所以不推荐使用for...in遍历数组。
数组的遍历可以考虑使用for循环或者while循环。
数组的forEach方法,也可以用来遍历数组。
var colors = ["red", "green", "blue"];
colors.forEach(function(color) {
console.log(color);
});
// red
// green
// blue
数组的空位
当数组的某个位置是空元素,即两个逗号之间没有任何值,我们称该数组存在空位。
var a = [1, , 1];
a.length // 3
上面代码表明,数组的空位不影响length属性。需要注意的是如果最后一个元素后面有逗号,并不会产生空位。数组的空位可以读取,返回undefined,使用delete命令删除一个数组成员,会形成空位,并且不会影响length属性。
数组的某个位置是空位,与某个位置是undefined,是不一样的。如果是空位,使用数组的forEach方法、for...in结构、以及Object.keys方法进行遍历,空位会被跳过。
var a = [, , , ];
a.forEach(function(x, i) {
console.log(x + "." + i);
}); //无任何输出
for (var i in a) {
console.log(i);
}//无任何输出
Object.keys(a); // []
而如果某个位置是undefined,遍历的时候就不会被跳过。
var a = [undefined, undefined, undefined];
a.forEach(function (x, i) {
console.log(x + "." + i);
});
// 0.undefined
...
类似数组的对象
var obj = {
0: "a",
1: "b",
2: "c",
length: 3
};
obj.push("d"); // TypeError: obj.push is not a function
如上所示的对象,语法上称为类似数组的对象。但是类似数组的对象并不是数组,因为它们不具备数组特有的方法。
典型的类似数组的对象有函数的arguments对象,以及大多数DOM元素集,还有字符串。
**数组的slice方法可以将类似数组的对象变成真正的数组。
var arr = Array.prototype.slice.call(arrayLike);
除了转为真正的数组,类似数组的对象还有一个办法可以使用数组的方法,就是通过call()把数组的方法放到对象上面。
function print(value, index) {
console.log(index + ":" + value);
}
Array.prototype.forEach.call(arrayLike, print);
上面代码中,arrayLike代表一个类似数组的对象,本来是不可以使用数组的forEach()方法的,但是通过call(),可以把forEach()嫁接到arrayLike上面调用。
下面这种方法,在arguments对象上面调用forEach方法。
function logArgs() {
Array.prototype.forEach.call(arguments, function (elem, i){
console.log(i + ". " + elem);
}) ;
}
// 等同于
function logArgs() {
for (var i = 0; i < arguments.length; i++) {
console.log(i + ". " + arguments[i]);
}
}
字符串也可以用Array.protptype.forEach.call遍历。
Array.prototype.forEach.call('abc' + function(chr) {
console.log(chr);
});
这种方法比直接使用数组原生的forEach要慢,所以最好还是先将类似数组的对象转成真正的数组,然后再直接调用数组的forEach方法。