我注意到,即使对于小型数组,本机forEach有时也会出现太慢的情况。请看下面的示例:
var a = [], b = [];
a[1234567] = 'foo';
b[10] = 'bar';
a.forEach(function(arg1, arg2) { console.log(arg1, arg2); }); //1
//vs
b.forEach(function(arg1, arg2) { console.log(arg1, arg2); }); //2在我的铬(25.0.1364.160 Ubuntu12.04)中,第1行和第2行的执行时间是不同的数量级。我知道a的长度等于1234568,而对于b,它仅仅等于10。但是原生forEach实现是否如此天真?a和b都只由一个元素组成。如何解释这种行为?
发布于 2013-06-08 13:25:10
这是因为a的长度实际上是1234568,所以你必须循环超过1234568个元素,因为你怎么能确保没有这些元素呢?
var a = []
a[1234567] = 'foo'
console.log(a.length) // 1234568因此,它正在循环超过1234566的nothing和1 'foo',而数组b只循环在9 "nothing"s和一个'bar'上。
当foreach试图读取a[0]时,它会意识到它不在那里,因为a在索引0上什么都没有。因此,foreach这样想:
I'm going to see what a[0] is!
Oh no! It's not there!
I'm going to see what a[1] is!
Oh no! It's not there!
I'm going to see what a[2] is!
Oh no! It's not there!
...
I'm going to see what a[1234567] is!
Yaaaaay! I found it! Now I'll print it!这就是为什么要花这么长时间。
发布于 2013-06-08 13:25:39
forEach遍历数组的全部长度,跳过不存在的元素。虽然a和b只包含一个元素,但它们的length很大,因此很难迭代forEach。
毕竟,它在规范中!ES5 15.4.4.18 Array.prototype.forEach节选
6)设k为0。 7)重复,而k< len
为了演示这一点,让我们看看火狐的SpiderMonkey是如何实现这些步骤的:
/* Steps 6-7. */
/* Steps a (implicit), and d. */
for (var k = 0; k < len; k++) {
/* Step b */
if (k in O) {
/* Step c. */
callFunction(callbackfn, T, O[k], k, O);
}
}您可以清楚地看到k从0到len的循环,这是性能问题的基础。对于几乎所有的k,k in O都会生成false,但您仍然会感受到一百万次迭代和一百万次k in O测试的影响。
在编写本报告时,这里是指向SpiderMonkey和V8实现的链接,以供参考。
发布于 2013-06-08 14:02:25
但是,原生
forEach实现是否如此天真呢?a和b都只包含一个元素。这个行为…怎么可能要解释吗?
它是在ECMAScript语言规范,5.1版,第15.4.4.18节中指定的。
当使用一个或两个参数调用
forEach方法时,将执行以下步骤:
ToObject的结果,传递这个值作为参数。"length"调用O的[[Get]]内部方法的结果。ToUint32(lenValue).IsCallable(callbackfn)是false,则抛出TypeError异常。ToString(k).
让kPresent是调用带有参数Pk的O的[[HasProperty]]内部方法的结果。
如果kPresent是真,那么
让kValue是调用带有参数Pk的O的[[Get]]内部方法的结果。
二、调用[[Call]]的回调函数的内部方法,以T作为--值和包含kValue、k和O的参数列表。d.将k增加1。
步骤6和步骤7需要一个一致的实现来迭代所有索引,从第一个索引0到最后一个索引a.length - 1,而不管是否有该索引的数组元素。这解释了为什么如果最后一个索引是一个大数,那么forEach方法调用会花费这么长的时间。
但是,由于在步骤7b (实现)中,[[HasProperty]]内部方法必须对没有数组元素的索引返回false,因此这些索引不调用回调回调。这解释了为什么在执行console.log方法调用时只有一个forEach调用。
https://stackoverflow.com/questions/16999929
复制相似问题