如何在类数组中使用数组的方法?
这里记点笔记,仅供学习参考。
判定数组
1. Array.isArray( )
给定一个未知的对象,判断它是否为数组?
我们通常用数组的一些特性来进行判断。在ES5中,可以使用 Array.isArray()
函数来做这件事:
Array.isArray([]); // true
Array.isArray({}); // false
但是在ES5之前,typeof
在这里却没什么用。对于数组,它的返回值为一个对象(对于除了函数以外的所有值都是如此)。
2. instanceof 操作符
instanceof
操作符也只能用语简单的情形:
[] instanceof Array // true
({}) instanceof Array // false
但使用 instanceof
的问题在于,web浏览器可能会有多个窗口存在,每个窗口都偶有自己的一个JavaScript环境,有自己的全局对象。并且,每个全局对象都有自己的一组构造函数。因此一个窗口中的对象将不可能是另外窗体中的构造函数实例。窗体之间的混淆不常发生,但这个问题足以证明 instaceof
操作符不能视为一个可靠的数组检测方法。
3. 检测类属性
对于数组而言,数组的属性总是“Array”,因此在ES3中的isArray()
函数的代码可以这样写:
var isArray = Array.isArray || function(o) {
return typeof o === "object" &&
Object.prototype.toString.call(o) === "[object Array]";
}
实际上,这里的类属性检测就是ES5中 Array.isArray()
函数所做的事情。
数组
在JavaScript中,数组有一些特性是其他对象所没有的:
- 当有新元素添加到列表中时,自动更新 length 属性。
- 设置 length 为一个较小的值将截断数组。
- 从 Array.prototype 中继承一些有用的方法。
- 其类属性为 “Array”。
这些特性让 JavaScript 数组和常见的对象有明显的区别。但是它们不是定义数组的本质特性。一种常常完全合理的看法把拥有一个数组为 length 属性和对应非负整数属性的对象看做一种类型的数组。
类数组
这些拥有length属性、并且非负整数属性的对象可以看做是“类数组”。
对于真正数组的遍历,很多数组算法针对类数组对象工作,也可以像针对真正的数组一样。
以下代码是为一个常规对象增加了一些属性使其变为类数组对象,然后遍历生成的伪数组的“元素”:
var a = {}; // 从一个空对象开始
var i= 0; // 添加一些属性,使其成为“类数组”
while(i < 10) {
a[i] = i * i;
i++;
}
a.length = i;
现在,把它当做真正的数组去遍历它:
var total = 0;
for(var j = 0; j < a.length; J++) {
total += a[j];
}
在客户端 JavaScript 中,一些 DOM 方法(如,document.getElementByTagName()
)也返回类数组对象。下面的函数可以用来检测类数组对象:
- 判定o是否是一个类数组对象
- 字符串和函数都有length 属性,但是它们可以用 typeof 检测将其排除。
- 在客户端 JavaScript 中,DOM 文本结点也可以有 length 属性,需要用额外的 nodeType != 3 将其排除
function isArrayLike(o) {
if (o&& // o 非 null 、undefined
typeof o === "object" && // o 是对象
o.length >= o && // o.length 是有限数值
o.length === Math.floor(o.length) && // o.length 是整数
o.length < 4294967296 ) // o.lengrh < 2^32
return true; // o 是类数组
else
return false; // o 不是
}
类数组对象使用数组方法
JavaScript 数组的方法是特意定义为通用的,因此它们不仅应用在真正的数组上,而且,在类数组上也可以使用。
- 在ES5中,所有数组的方法都是通用的。
- 在ES3中,除了
toString()
和toLocaleString()
以外的所有方法也是通用的。 - 类数组对象没有继承自
Array.prototype
,那就不能在它们上面直接调用数组的方法。尽管如此,也可以间接的使用Function.call
方法调用:
var a = {"0": "a", "1": "b", "2": "c", length: 3}; // 类数组对象
Array.prototype.join.call(a, "+"); // => "a+b+c"
Array.prototype.slice.call(a, 0); // => ["a", "b", "c"] 真正的数组
Array.prototype.map.call(a, function(x) {
return x.toUpperCase(); // => ["A", "B", "C"]
})
ES5 数组的方法是在 Firefox 1.5 中引入的,同时 Firefox 将这些方法在 Array 的构造函数上直接定义为数组。即可以写为:
var a = {"0": "a", "1": "b", "2": "c", length: 3}; // 类数组对象
Array.join(a, "+"); // => "a+b+c"
Array.slice(a, 0); // => ["a", "b", "c"] 真正的数组
Array.map(a, function(x) {
return x.toUpperCase(); // => ["A", "B", "C"]
})
总结
当用在类数组对象上时,数组的方法的静态函数版本非常有用。