数组

原文链接

1 本质

本质上,数组属于一种特殊的对象,typeof 返回数组的类型是 object 。

var arr = ['a', 'b', 'c'];

Object.keys(arr)
// ["0", "1", "2"]

由此可见,数组的键就是字符串状态的自然数。单独的数值不能作为标识符,数组成员只能用方括号读取。

2 长度

只要是数组,就一定有长度属性 length 。长度是可写的,如果人为设置长度小于当前元素个数,该数组会自动抹除超出范围的元素。清空数组的一个有效方法就是将长度置零。如果人为设置长度大于当前元素个数,该数组会自动用 undefined 补足。

3 空位

数组两个逗号之间没有任何值,称该数组存在空位 hole 。计算长度时不过滤空位,所以用 length 属性遍历时一定要小心。 forEach()for...in 以及 Object.keys() 可以跳过空位,但不会跳过 undefined 。

var a = [1, , 1];
a.length // 3

末端的逗号不产生空位。使用 delete 删除数组成员时会形成空位,并且不会影响长度。

var a = [1, 2, 3];
delete a[1];

a[1] // undefined
a.length // 3

4 类似数组的对象

如果一个对象所有键都是自然数,并且有长度属性,就称之为“类似数组的对象”。“类似数组的对象”并不是数组,因为它们不具备数组特有的方法,而且它们的长度属性不会随成员变化而变化。

function args() { return arguments }
var arrayLike = args('a', 'b');

数组的 slice 方法可以将“类似数组的对象”变成真正的数组。

var arr = Array.prototype.slice.call(arrayLike);

除了转为真正的数组,“类似数组的对象”还可以通过 call() 把数组的方法嫁接到对象上面。

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]);
  }
}

注意,这种调用比数组原生方法慢,建议先转成真正的数组。

5 字符串与数组

字符串与数组有一定的相通性,但字符串的内部字符无法通过数组改变,操作会默默地失败。

var s = 'hello';

delete s[0];
s // "hello"

s[1] = 'a';
s // "hello"

s[5] = '!';
s // "hello"