数组字面量
和JavaScript中大多数“东西”一样,数组也是对象。可以通过内置构造函数Array()
来创建数组,也可以通过字面量形式创建,就像对象字面量那样。而且更推荐使用字面量创建数组。
这里的示例代码给出了创建两个具有相同元素的数组的两种方法,使用Array()
和使用字面量模式:
// 有三个元素的数组
// 注意:这是反模式
var a = new Array("itsy", "bitsy", "spider");
// 完全相同的数组
var a = ["itsy", "bitsy", "spider"];
console.log(typeof a); // "object",因为数组也是对象
console.log(a.constructor === Array); // true
数组字面量语法
数组字面量写法非常简单:整个数组使用方括号括起来,数组元素之间使用逗号分隔。数组元素可以是任意类型,包括数组和对象。
数组字面量语法简单直观而且优雅,毕竟数组只是从0开始索引的一些值的集合,完全没必要引入构造器和new
运算符(还要写更多的代码)。
Array()构造函数的“陷阱”
我们对new Array()
敬而远之还有一个原因,就是为了避免构造函数带来的陷阱。
如果给Array()
构造函数传入一个数字,这个数字并不会成为数组的第一个元素,而是设置了数组的长度。也就是说,new Array(3)
创建了一个长度为3的数组,而不是某个元素是3。如果你访问数组的任意元素都会得到undefined
,因为元素并不存在。下面的示例代码展示了字面量和构造函数的区别:
// 含有1个元素的数组
var a = [3];
console.log(a.length); // 1
console.log(a[0]); // 3
// 含有3个元素的数组
var a = new Array(3);
console.log(a.length); // 3
console.log(typeof a[0]); // "undefined"
构造函数的行为可能有一点出乎意料,但当给new Array()
传入一个浮点数时情况就更糟糕了,这时会出错(译注:给new Array()传入浮点数会报“范围错误”RangError),因为数组长度不可能是浮点数。
// 使用数组字面量
var a = [3.14];
console.log(a[0]); // 3.14
var a = new Array(3.14); // RangeError: invalid array length
console.log(typeof a); // "undefined"
为了避免在运行时动态创建数组时出现这种错误,强烈推荐使用数组字面量来代替new Array()
。
有些人用
Array()
构造器来做一些有意思的事情,比如用来生成重复字符串。下面这行代码返回的字符串包含255个空格(请读者思考为什么不是256个空格)。var white = new Array(256).join(' ');
检查是否数组
如果typeof
的操作数是数组的话,将返回“object”。
console.log(typeof [1, 2]); // "object"
这个结果勉强说得过去,毕竟数组也是一种对象,但对我们来说这个结果却没什么用,实际上你往往是需要知道一个值是不是真正的数组。有时候你会见到一些检查数组的方法:检查length
属性、检查数组方法比如slice()
等等,但这些方法非常脆弱,非数组的对象也可以拥有这些同名的属性。还有些人使用instanceof Array
来判断数组,但这种方法在某些版本的IE里的多个iframe的场景中会出问题(译注:原因就是在不同iframe中创建的数组不会相互共享其prototype
属性)。
ECMAScript5定义了一个新的方法Array.isArray()
,如果参数是数组的话就返回true。比如:
Array.isArray([]); // true
// 尝试用一个类似数组的对象去测试
Array.isArray({
length: 1,
"0": 1,
slice: function () {}
}); // false
如果你的开发环境不支持ECMAScript5,可以通过Object.prototype.toString()
方法来代替。如调用toString
的call()
方法并传入数组上下文,将返回字符串“[object Array]”。如果传入对象上下文,则返回字符串“[object Object]”。因此可以这样做:
if (typeof Array.isArray === "undefined") {
Array.isArray = function (arg) {
return Object.prototype.toString.call(arg) === "[object Array]";
};
}