javascript中类似数组的对象

时间:2009-12-28 20:27:07

标签: javascript google-closure-library

通过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;
}

在常规阵列上执行此操作会带来什么好处?

6 个答案:

答案 0 :(得分:3)

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

我可以想到两个原因:

  1. 内存使用 - 如果数组由分配n个元素的实现支持,当它达到它的限制时,它会增加一些因素来增加它的容量,从而浪费capacity - length内存
  2. cpu time - 实现者选择插入速度超过随机访问速度 - 此方法的返回更有可能比随机访问顺序迭代,并且在插入时调整数组大小会导致具有cpu惩罚的分配复制释放
  3. 我打赌在其他JavaScript库中会找到类似的代码,并且它是基准测试的结果,并且可以在不同的浏览器中找到最适合的解决方案。

    经贾斯汀评论

    后编辑

    进一步使用Google搜索后,似乎类似数组的对象在JavaScript开发人员中很常见:checkout JavaScript:David Flanagan的权威指南,它有一个完整的sub-chapter on Array-like objectsthese guys也提到了它们。

    没有提到为什么要选择类似数组的数组对象。这可能是一个很好的问题。

    因此,第三个选项可能是关键:遵守JavaScript API的规范。

答案 1 :(得分: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-writevalue的大小和类型对测试无关紧要。大量(1kb)value用于说服那些不熟悉JavaScript功能的读者。

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

我认为alert(typeof []);返回“object”后没有任何区别。每次我看到这样的东西(特别是来自Goog),我不得不认为它是为了提升性能。

它实际上是在没有pushpop等所有继承函数的情况下返回数组。

答案 4 :(得分:0)

goog.dom.getElementsByTagNameAndClass_

您正在处理HTML集合。 arrayLike对象是节点列表的 snapshot ,而不是“live”集合对象。它使得它与索引数组一样容易使用,如果在循环其成员时创建或删除节点,则不太可能导致复杂化。

答案 5 :(得分:-3)

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