javascript中的类数组对象
通过从闭包库中查找dom.js源代码,我发现了以下内容(在javascript中的类数组对象,javascript,google-closure-library,Javascript,Google Closure Library,通过从闭包库中查找dom.js源代码,我发现了以下内容(在goog.dom.getElementsByTagNameAndClass中): 在常规数组上这样做有什么好处?据我所知,没有任何好处,因为除了创建语法之外,它和“常规数组”实际上没有任何区别——所有Javascript对象都是关联数组。在这种情况下,我的猜测是类似于[len++]=el是对实际光线.推送(el)的优化。然而,在完成一个简单的基准测试(下面提供的代码结果)之后,似乎这种方法实际上比使用标准数组(使用push方法以及相同的构
goog.dom.getElementsByTagNameAndClass中):
在常规数组上这样做有什么好处?据我所知,没有任何好处,因为除了创建语法之外,它和“常规数组”实际上没有任何区别——所有Javascript对象都是关联数组。在这种情况下,我的猜测是类似于[len++]=el
是对实际光线.推送(el)
的优化。然而,在完成一个简单的基准测试(下面提供的代码结果)之后,似乎这种方法实际上比使用标准数组(使用push
方法以及相同的构造技术)要慢
结果(摘自OS X 10.5.8,FF 3.5.6)*:
总之,我无法理解闭包在这种情况下为什么使用关联数组。这可能是有原因的(例如,这项技术在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");
var MAX=100000,i=0,
a1={},a2=[],a3=[],
value=“”;
对于(i=0;i代码作者使用空JavaScript对象作为类似数组的对象的基础,即可以通过索引访问并具有长度属性的对象
我可以想到两个原因:
内存使用-如果数组由分配n个元素的实现支持,当它达到极限时,它会以某种方式增长以增加容量,从而浪费内存的容量-长度
cpu时间—实现者选择插入速度而不是随机访问速度—此方法的返回更有可能按顺序迭代而不是随机访问,并且在插入中调整数组的大小会导致分配副本解除分配,这会导致cpu损失
我敢打赌,在其他JavaScript库中也会发现类似的代码,这是在不同浏览器之间进行基准测试并找到最适合的解决方案的结果
贾斯汀评论后编辑
在进一步的谷歌搜索中,似乎类似数组的对象在JavaScript开发人员中很常见:David Flanagan的权威指南checkout JavaScript:the Financial guide,它有一个完整的框架。也请提及它们
没有提到为什么人们更喜欢数组,比如vs数组对象。这可能是一个很好的问题
因此,第三个选项可能是关键:遵守JavaScript API的规范。我看不出有什么区别,因为警报(typeof[]);
返回“object”。每当我看到这样的东西(特别是从谷歌上看到的),我都不得不假设这是为了提高性能
它本质上是在不使用所有继承函数(如push
和pop
)的情况下重新提取数组
goog.dom.getElementsByTagNameAndClass_
您正在处理html集合。arrayLike对象是节点列表的快照,而不是“live”集合对象。它与索引数组一样易于处理,并且如果在循环遍历其成员时创建或删除节点,则不太可能导致复杂情况。我认为此示例创建了类似数组的对象而不是真正的数组,因为其他DOM方法也返回类似数组的对象(NodeList)
在API中始终使用“类似数组”迫使开发人员避免使用特定于数组的方法(而是使用goog.array
),因此,当以后有人决定将GetElementsByTagname和Class调用更改为(例如)getElementByTagName时,会出现较少的问题。不完全正确。对象/关联数组没有长度属性,这就是闭包库在这种情况下添加它的原因(例如:控制台.log({}.length,[.length)
=“未定义的0”)。此外,数组([])具有更广泛的方法集(请参见Array.prototype)。数组扩展对象(关联数组);它添加了所有数组方法,并跟踪长度。请注意,length
没有跟踪非整数键控对象。是PHP,它们与我的想法完全相同。结果证明我们都错了。请参阅我的基准事实上,上次我检查时,Google Closure根本没有针对性能进行优化,并且更像是一个遗留代码。容量不一定随着每次插入而增长。每当达到容器的容量时,将容量增加一个大于1的值是一种常见的优化。我还没有查看实际引擎的代码,但我愿意投入资金进行优化。至于CPU时间,我的基准测试显示相反,假设它只在FF 3.5.6中。你当然是对的,但我不是(有意的)暗示容量会随着每次插入而增加…无论何时进行基准测试,请记住要针对IE 6进行基准测试。您看到的许多奇怪的性能黑客可能是为了解决IE 6的一些糟糕的性能特征,而在其他浏览器上提供的好处微乎其微。确实,我知道这一点。但是,正如我所说,我目前在Mac上,无法在各种浏览器上进行测试。没错,布莱恩。由于浏览器的市场份额,在性能上支持IE是有道理的(有很多人讨厌IE,但事实就是事实)。此外,一定要用谷歌的V8引擎运行此测试。
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");
goog.dom.getElementsByTagNameAndClass_