哪个更快,For循环还是.hasOwnProperty()?

10

我正在处理一个项目,需要从大量的用户数据中提取一份被排除的用户列表。这让我在想:使用双重for循环和包含排除id的数组是否更快?还是将id放入对象属性中并使用.hasOwnProperty()更快?

var mainList = LARGE JSON OBJECT OF DATA.
var eArray = ["123456","234567","345678","456789","012345"];
var eObject = {"123456":"0","234567":"0","345678":"0","456789":"0","012345":"0"};

使用双重for循环方法:

for(i=0; i < mainList.length; i++){
    for(j=0; j < eArray.length; j++){
        if(mainList[i]['id'] === eArray[j]){
           //Do Something
        }
    }
}

使用.hasOwnProperty()方法:

for(i=0; i < mainList.length; i++){
    if(eObject.hasOwnProperty(mainList[i]['id'])){
       //Do Something
    }
}

我意识到有其他方法可以使循环更快,比如在变量中存储长度。 我试图简化这个过程。

感谢任何信息。


嗯,如果你想一想的话,.hasOwnProperty()方法更快是有道理的,因为少了一个循环。 - Shawn31313
@Shawn31313 我也是这么想的。但我不确定.hasOwnProperty()如何循环遍历对象的属性。 - James
4个回答

8

你错过了第三种更快速的替代方案。假设你没有对 Object.prototype 进行任何调整,并且ID不太可能是原型值(如 valueOf 等),你可以直接使用一个类似下面的 for 循环:

for(var i=0; i < mainList.length; i++)
{
    if (eObject[mainList[i].id] !== undefined)
    {//or typeof eObject[mainList[i].id] !== 'undefined'
        //do something
    }
}

请查看更新后的JSPref,它是迄今为止最快的方式(57,252,850次/秒对于双循环的17,503,538次/秒)


如果 eObject[mainList[i].id] 等于 0 呢?目前所有 eObject 的值都等于 0。 - Shawn31313
@Shawn31313:增加了额外的检查,编辑了JSPref以反映这一点。 - Elias Van Ootegem
如果eObject不为null,则可以使用(!eObject [mainList [i] .id])2倍速度更快,同时在for循环中缓存长度。 - cocco
@cocco:这取决于原帖发布者的决定。我不知道对象可能包含什么或不包含什么... - Elias Van Ootegem
刚注意到你的 valueOf 评论。我什么也没说。 - Jorge Fuentes González

7
如果你仔细想想的话,使用.hasOwnProperty()方法会更快,因为它只使用了1个for loop

错误写法

实际上我有些惊讶,我本来以为双重循环会比较慢。但我猜你不能低估一个for loop的速度。

双重循环

虽然对我来说这似乎是最慢的,但实际上它是最快的,测试结果为7,291,083 ops/sec

.hasOwnProperty()

我可以看出来这可能会比较慢,因为函数比语句慢。测试结果为1,730,588 ops/sec

if..in

@Geuis的答案包含了if..in语句,并且我想测试一下它的速度,因为这似乎是最快的,但测试结果为2,715,091 ops/sec,它仍然无法打败for循环。

结论

for循环非常快。双重循环比使用.hasOwnProperty()快了4倍以上,比使用if..in条件快了近3倍。然而,表现并不明显;所以速度真的那么重要吗?在我看来,使用if..in方法是最好的选择。

你可以在浏览器中自行测试,我使用的是Google Chrome 28

更新

重要的一点是,使用for..in声明会给你最佳性能。


在您的 jspref 中添加了一个替代 hasOwnProperty 的方法,它比双重循环更快(速度提高了约3倍)。 - Elias Van Ootegem
我没有看到任何添加@EliasVanOotegem。 - Shawn31313
这个答案是不正确的,也没有包含我在答案中提到的最快和最简单的方法。使用 indexOf 和 val > -1 检查。在这里查看更新后的性能测试:http://jsperf.com/stackoverflow-for-vs-hasownproperty/5。双重循环始终比更简单、直接的方法慢。 - Geuis
1
这个回答哪里不正确呢?问题明确问到“哪个更快,For循环还是.hasOwnProperty()方法?”我已经回答了这个问题。祝你愉快! - Shawn31313

1

修改以显示未来互联网遍历者的正确代码:访问http://jsperf.com/stackoverflow-for-vs-hasownproperty/5进行比较。

var testVal = 'BigBrownFox',
    arr = [1,4,'asd','BigBrownFox',9];

if( arr.indexOf('testVal') > -1 ){
    //do something
}

测试一个数组中的值是否存在于另一个数组中:

var testVal = ['BigBrownFox'],
    arr = [1,4,'asd','BigBrownFox',9];

for(var i=0, len=testVal.length; i<len; i++){

    if( arr.indexOf(testVal[i]) > -1 ){
        //do something
    }

}

实际上,在这两种情况下,你的方法都有些错误。

如果你正在使用数组,请使用indexOf函数。如果测试值存在,则返回其索引。否则,如果未找到,则返回-1。根本不需要循环。

在对象的情况下,不需要使用.hasOwnProperty。是的,它可以达到你想要的效果,但过于复杂且速度较慢,因为你正在进行函数调用。

只需使用

var eObject = {"123456":"0","234567":"0","345678":"0","456789":"0","012345":"0"};
if( '234567' in eObject ){ //do something }

希望这能有所帮助。

从您的链接中:“_indexOf是ECMA-262标准的最新补充,因此它可能不会出现在所有浏览器中..._” - jahroy

0

在Chrome中,最快的循环是for循环。

在旧版/其他浏览器中,最快的循环是while循环。

特别是如果您缓存长度。(如果mainList很大,则非常重要)

由于我看到您的eObject中只有字符串,我建议使用(eObject[mainList[i].id])

这比(eObject[mainList[i].id] !== undefined)更快。

var i=mainList.length;
while(i--){
  if (eObject[mainList[i].id]) {
    //do something
  }
}

你有任何证据支持这些主张吗? - jahroy
给我一些时间,我会在Ubuntu、Mac、Windows、Firefox、Safari、Chrome、IE和移动设备上运行它。 - cocco
测试通过...看起来唯一怪异的结果来自Ubuntu上的Firefox,其中如果“in”是赢家。至于我的声明,我认为我是对的。 - cocco
我想知道你是否进行过任何基准测试来确认缓存数组长度是否有所影响。你声称这非常重要,而我会感到惊讶如果它根本没有任何影响。 - jahroy
是的,这确实有所不同...特别是在旧浏览器上处理大数组时...如果您不缓存每一次它都必须检查数组的长度。但在 Chrome 和现代浏览器中,他们可能添加了自动缓存系统,因为大多数人无法编写 JavaScript。 - cocco
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接