7

查看来自 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;
}

与常规数组相比,这样做有什么好处?

4

6 回答 6

3

代码的作者使用空 JavaScript 对象作为数组对象的基础,即可以通过索引访问并具有长度属性的对象。

我能想到的原因可能有两个:

  1. 内存使用 - 如果数组由分配 n 个元素的实现支持,当它达到它的限制时,它会增长一些因素以增加它的容量,从而浪费capacity - length内存
  2. cpu time - 实现者选择插入速度而不是随机访问速度 - 与随机访问相比,此方法的返回更有可能按顺序迭代,并且在插入时调整数组大小会导致分配-复制-释放,这会造成 cpu 损失

我敢打赌,类似的代码会在其他 JavaScript 库中找到,这是基准测试和找到最适合不同浏览器的解决方案的结果。

贾斯汀评论后编辑

进一步谷歌搜索后,类似数组的对象似乎在 JavaScript 开发人员中很常见:查看 JavaScript:David Flanagan 的权威指南,它有一个关于类数组对象的完整子章节这些 也提到了他们。

没有提到为什么要更喜欢类数组与数组对象。这可能是一个很好的问题。

所以第三个选项可能是关键:遵守 JavaScript API 的规范。

于 2009-12-28T21:30:43.687 回答
2

在这种情况下,我的猜测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");

由于 JavaScript 使用copy-on-write,因此大小和类型对value测试无关紧要。一个大的(1kb)用于说服那些不熟悉 JavaScript 的这个特性的读者。value

于 2009-12-28T21:17:46.643 回答
2

我认为这个例子创建了一个类数组对象而不是一个真正的数组,因为其他 DOM 方法也返回类数组对象(NodeList)。

在 API 中始终使用“array-likes”会迫使开发人员避免使用特定于数组的方法(goog.array改为使用),因此当有人后来决定将 getElementsByTagNameAndClass 调用更改为 getElementByTagName 时,陷阱就会减少。

于 2010-01-05T17:08:06.743 回答
0

我没有看到任何区别,因为alert(typeof []);返回“对象”。任何时候我看到这样的东西(尤其是来自 Goog),我不得不假设它是为了提高性能。

它本质上是在没有所有继承函数(例如push和)的情况下返回一个数组pop

于 2009-12-28T21:35:03.303 回答
0
goog.dom.getElementsByTagNameAndClass_

您正在处理 html 集合。arrayLike 对象是节点列表的快照,而不是“实时”集合对象。它使它像索引数组一样容易使用,并且如果您在循环访问其成员时创建或删除节点,则不太可能导致复杂化。

于 2009-12-28T23:35:58.100 回答
-3

据我所知,没有任何好处,因为除了创建语法之外,它与“常规数组”之间实际上没有任何区别——所有 Javascript 对象都是关联数组。

于 2009-12-28T20:35:16.603 回答