像JavaScript中的对象
通过Closure库查看dom.js源代码,我发现了这个(在goog.dom.getElementsByTagNameAndClass_
):
if (opt_class) {
var arrayLike = {};
var len = 0;
for (var i = 0, el; el = els[i]; i++) {
var className = el.className;
// Check if className has a split function since SVG className does not.
if (typeof className.split == 'function' &&
goog.array.contains(className.split(' '), opt_class)) {
arrayLike[len++] = el;
}
}
arrayLike.length = len;
return arrayLike;
}
在常规数组上做这件事会有什么好处?
代码的作者使用空的JavaScript对象作为像对象这样的数组的基础,即可以通过索引访问并具有长度属性的对象。
我可以想到两个原因:
capacity - length
内存的capacity - length
我敢打赌,在其他JavaScript库中可以找到类似的代码,并且它是基准测试的结果,并在不同浏览器中找到最适合的解决方案。
贾斯汀评论后编辑
在进一步的Google搜索中,似乎类似于数组的对象在JavaScript开发人员中很常见:checkout JavaScript:David Flanagan的权威指南,它有关于类似Array的对象的整个子章节。 这些人也提到他们。
没有提到为什么应该更喜欢类似数组的对象。 这可能是一个很好的SO问题。
所以第三个选择可能是关键:符合JavaScript API的规范。
在这种情况下,我的猜测是arrayLike[len++] = el
是对actualArray.push(el)
的优化。 然而,在做了一个简单的基准测试(结果下面提供的代码)之后,看起来这个方法实际上比使用push
方法的标准数组以及相同的构造技术要慢。
结果(来自OS X 10.5.8,FF 3.5.6)*:
push construction: 199ms (fastest)
indexed construction: 209ms
associative construction: 258ms (slowest)
总之,为什么Closure在这种情况下使用关联数组超出了我的想象。 可能有一个原因(例如,这种技术可能在Chrome中表现得更好,或者不太可疑,这种技术在未来的JavaScript引擎版本中可能会表现得更好),但在这种情况下我看不出有什么好理由。
*没有提供均值,因为从试运行到试运行的时间不同,但始终产生相同的顺序。 如果你有兴趣,你可以自己做。
基准代码:
var MAX = 100000, i = 0,
a1 = {}, a2 = [], a3 = [],
value = "";
for ( i=0; i<1024; ++i ) {
value += "a";
}
console.time("associative construction");
for ( i=0; i<MAX; ++i ) {
a1[i] = value;
}
a1.length = i;
console.timeEnd("associative construction");
console.time("push construction");
for ( i=0; i<MAX; ++i ) {
a2.push(value);
}
console.timeEnd("push construction");
console.time("indexed construction");
for ( i=0; i<MAX; ++i ) {
a3[i] = value;
}
console.timeEnd("indexed construction");
value
的大小和类型对于测试来说是微不足道的,因为JavaScript使用了写入时复制。 为了说服那些不熟悉JavaScript这一特性的读者,使用了一个大的(1kb) value
。
我认为这个例子创建了一个类似数组的对象,而不是一个真正的数组,因为其他的DOM方法也返回数组类对象(NodeList)。
在API中一直使用“数组 - goog.array
”迫使开发人员避免使用特定于数组的方法(使用goog.array
代替),因此当稍后某人决定将getElementsByTagNameAndClass调用更改为getElementByTagName时,会出现更少的陷阱。