数组

原文地址: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方法

posted @ 2018-11-16 18:15  上升的泡泡  阅读(131)  评论(0编辑  收藏  举报