Javascript .forEach vs Object.keys().forEach在稀疏数组上的性能

Javascript .forEach vs Object.keys().forEach在稀疏数组上的性能,javascript,arrays,performance,foreach,v8,Javascript,Arrays,Performance,Foreach,V8,如果我错了,请告诉我:array.forEach(callbackFunction)适用于稀疏数组。它不会对0和数组长度之间的每个索引执行callbackFunction,而只对实际位于数组中的键执行。并且(如果我错了,请告诉我)这些键正是对象所能提供的。键(数组)将提供给我。因此(告诉我为什么我错了)如果在array本身或Object.keys(array)上调用.forEach方法,应该没有什么区别。那么,究竟为什么会有这种性能差异呢?就好像在一种情况下,一个从零到长度的巨大的无意义循环会被

如果我错了,请告诉我:
array.forEach(callbackFunction)
适用于稀疏数组。它不会对0和数组长度之间的每个索引执行
callbackFunction
,而只对实际位于
数组中的键执行
。并且(如果我错了,请告诉我)这些键正是
对象所能提供的。键(数组)
将提供给我。因此(告诉我为什么我错了)如果在
array
本身或
Object.keys(array)
上调用
.forEach
方法,应该没有什么区别。那么,究竟为什么会有这种性能差异呢?就好像在一种情况下,一个从零到长度的巨大的无意义循环会被执行,而在另一种情况下则不会

显示性能差异的代码段:

函数doNothing(){}
CONSOLE=document.getElementById('CONSOLE');
arr=[];
arr[49888999]=42;
开始=性能。现在();
阿雷弗雷奇(不做任何事);
duration1=性能。现在()-开始;
开始=性能。现在();
对象键(arr)forEach(doNothing);
duration2=性能。现在()-开始;
CONSOLE.textContent=[duration1,duration2]。加入('\n')

好吧,好吧,好吧——所以这只是我们必须忍受的事情之一;我不想听,但这是正确的答案

我将继续不看说明书,有时会感到困惑。不,我不是在推荐那种行为,这只是我打滚的方式。在控制台上试用它对我来说更有意义,它肯定更有趣,而规格往往会让我睡着。谢天谢地,人是不同的,不是每个人都是这样

也许一个更有趣的问题是如何在实践中处理这一现象。例如,如果我必须处理“产品51472的2项和产品81369的1项”中的“稀疏数组”,我将使用键为51472和81369的对象(
{}
),而不是数组(
[]

仅仅因为所有键恰好都是非负整数就将其设置为数组是一个坏主意这是过去1万年来最糟糕的主意-因为你有
.forEach
,这是一个假朋友

2相关问题:

似乎是因为,在一种情况下,将执行从零到长度的巨大无意义循环,但在另一种情况下不会执行


根据报告:

  • .forEach
    方法将通过其
    .length
    属性在所有数组元素中循环
  • 传递给
    .forEach
    的回调仅在元素不为空时调用
  • 要演示这一点,您只需执行以下操作:

    函数doNothing(){}
    让我们表演;
    log('5000万长度的数组和1个非空元素:');
    常数a=[];
    a[4999999]=“a”;
    console.log('a.length:',a.length);
    perf=performance.now();
    a、 forEach(doNothing);
    log('a:',performance.now()-perf);
    控制台日志(“”);
    log('长度为0的数组:');
    常数b=[];
    b、 foo='a';
    console.log('b.length:',b.length);
    perf=performance.now();
    b、 forEach(doNothing);
    log('b:',performance.now()-perf);
    控制台日志(“”);
    log('长度为5000万且非空元素为0的数组:');
    常数c=[];
    c、 长度=50000000;
    console.log('c.length:',c.length);
    perf=performance.now();
    c、 forEach(doNothing);
    
    log('c:',performance.now()-perf)这是JS引擎的一个实现细节。根据环境的不同,有几种不同的JS引擎在使用,它们使用不同的优化策略,因此您的问题没有通用的答案。但是我应该注意,仅仅因为没有为空索引调用回调并不意味着引擎没有对其进行迭代。毕竟,它必须以某种方式确定它是否为空。forEach仍然必须迭代从0到.length的所有数值。例如,如果你做了
    Object.defineProperty(arr,'42',{enumerable:false})
    ,它仍然应该传递这个不可枚举的
    42
    索引,如果你做了
    arr[“foo”]=bar
    ,它应该忽略这个
    foo
    属性;a、 foo=“bar”可以。我也已经给出了这样一个例子:
    Object.defineProperty(arr,'42',{enumerable:false})
    在数组上使用
    Object.keys()
    对我来说似乎是一种反模式。如果我发现自己处于这种情况,我可能会使用普通对象而不是稀疏数组。引擎可能会为这种情况添加一条快速路径,但只是因为有更紧迫的问题需要解决,所以还没有找到解决方法。Array.prototype.forEach实现非常复杂,因为它是。。。