JavaScript:原生forEach vs native forEach

Iva*_*hko 6 javascript performance foreach

我注意到,即使对于小型阵列,原生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
Run Code Online (Sandbox Code Playgroud)

在我的Chromium(25.0.1364.160 Ubuntu 12.04)中,第1行和第2行的执行时间是不同的数量级.我知道a的长度等于1234568,而b等于10 等等.但是原生的forEach实现是如此幼稚吗?既一个b是仅由一个元件构成.如何解释这种行为?

Doo*_*nob 10

那是因为a长度实际上是1234568,所以你必须循环超过1234568个元素,因为你怎么能确定元素不在那里?

var a = []
a[1234567] = 'foo'
console.log(a.length) // 1234568
Run Code Online (Sandbox Code Playgroud)

因此,它循环超过1234566的无和1 'foo',vs数组b只循环超过9"无"和a '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!
Run Code Online (Sandbox Code Playgroud)

这就是为什么它需要这么长时间.

  • @PointedEars请详细说明?答案的哪一部分是错的? (3认同)
  • 该数组不包含`undefined`元素.读取属性只会产生`undefined`,就像任何其他不存在的属性一样. (3认同)

Mat*_*ens 5

forEach遍历数组的整个长度,在途中跳过不存在的元素.虽然a并且b只包含一个元素,但它们length很大,因此您需要forEach花费很多时间进行迭代.

毕竟,它在规范中!ES5 15.4.4.18 Array.prototype.forEach的摘录:

6)设k为0.

7)重复,而k <len

为了演示这一点,让我们看看Firefox的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以清楚地看到的循环k,从0len其谎言在您的性能问题的基础.对于几乎所有的k,k in O收益率false,但你还是觉得一百万次迭代的影响,以及一百万k in O测试.

作为参考,这里是编写本文时SpiderMonkeyV8实现的链接.