Javascript for..in 与 for 循环性能

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13645890/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 19:21:41  来源:igfitidea点击:

Javascript for..in vs for loop performance

javascript

提问by Josnidhin

I was clustering around 40000 points using kmean algorithm. In the first version of the program I wrote the euclidean distance function like this

我使用 kmean 算法对大约 40000 个点进行了聚类。在程序的第一个版本中,我写了这样的欧几里德距离函数

var euclideanDistance = function( p1, p2 ) { // p1.length === p2.length == 3
    var sum = 0;
    for( var i in p1 ){
        sum += Math.pow( p1[i] - p2[i], 2 );
    }
    return Math.sqrt( sum );
};

The overall program was quite slow taking on average 7sec to execute. After some profiling I rewrote the above function like this

整个程序很慢,平均执行时间为 7 秒。经过一些分析后,我像这样重写了上面的函数

var euclideanDistance = function( p1, p2 ) { // p1.length === p2.length == 3
    var sum = 0;
    for( var i = 0; i < p1.length; i++ ) {
        sum += Math.pow( p1[i] - p2[i], 2 );
    }
    return Math.sqrt( sum );
};

Now the programs on average take around 400ms. That's a huge time difference just because of the way I wrote the for loop. I normally don't use for..inloop for arrays but for some reason I used it while writing this function.

现在程序平均需要大约 400 毫秒。这是一个巨大的时间差异,因为我编写 for 循环的方式。我通常不会for..in对数组使用循环,但出于某种原因,我在编写此函数时使用了它。

Can someone explain why there is this huge difference in performance between these 2 styles?

有人可以解释为什么这两种风格在性能上存在巨大差异吗?

回答by Esailija

Look at what's happening differently in each iteration:

查看每次迭代中发生的不同情况:

for( var i = 0; i < p1.length; i++ ) 
  1. Check if i < p1.length
  2. Increment iby one
  1. 检查是否 i < p1.length
  2. 增量i由一个

Very simple and fast.

非常简单和快速。

Now look at what's happening in each iteration for this:

现在看看每次迭代中发生了什么:

for( var i in p1 )

for( var i in p1 )

Repeat

  1. Let P be the name of the next property of obj whose [[Enumerable]] attribute is true. If there is no such property, return (normal, V, empty).

重复

  1. 设 P 是 obj 的下一个属性的名称,其 [[Enumerable]] 属性为真。如果没有这样的属性,则返回(normal, V, empty)。

It has to find next property in the object that is enumerable. With your array you know that this can be achieved by a simple integer increment, where as the algorithm to find next enumerable is most likely not that simple because it has to work on arbitrary object and its prototype chain keys.

它必须在可枚举的对象中找到下一个属性。对于您的数组,您知道这可以通过简单的整数增量来实现,而查找下一个可枚举的算法很可能并不那么简单,因为它必须处理任意对象及其原型链键。

回答by gkiely

As a side note, if you cache the length of p1:

作为旁注,如果您缓存 p1 的长度:

var plen = p1.length;
for( var i = 0; i < plen; i++ )

you will get a slight speed increase.

你会得到轻微的速度提升。

...And if you memoize the function, it will cache results, so if the user tries the same numbers you will see a massive speed increase.

...如果你记住这个函数,它会缓存结果,所以如果用户尝试相同的数字,你会看到速度大幅提高。

var eDistance = memoize(euclideanDistance);  

function memoize( fn ) {  
    return function () {  
        var args = Array.prototype.slice.call(arguments),  
            hash = "",  
            i = args.length;  
        currentArg = null;  
        while (i--) {  
            currentArg = args[i];  
            hash += (currentArg === Object(currentArg)) ?  
            JSON.stringify(currentArg) : currentArg;  
            fn.memoize || (fn.memoize = {});  
        }  
        return (hash in fn.memoize) ? fn.memoize[hash] :  
        fn.memoize[hash] = fn.apply(this, args);  
    };  
}

eDistance([1,2,3],[1,2,3]);
eDistance([1,2,3],[1,2,3]); //Returns cached value

credit: http://addyosmani.com/blog/faster-javascript-memoization/

信用:http: //addyosmani.com/blog/faster-javascript-memoization/

回答by op1ekun

First You should be aware of thisin the case of for/in and arrays. No big deal if You know what You are doing.

首先,对于 for/in 和数组,您应该意识到这一点。如果您知道自己在做什么,那没什么大不了的。

I run some very simple tests to show the difference in performance between different loops: http://jsben.ch/#/BQhED

我运行了一些非常简单的测试来显示不同循环之间的性能差异:http: //jsben.ch/#/BQhED

That is why prefer to use classic for loop for arrays.

这就是为什么更喜欢对数组使用经典的 for 循环的原因。

回答by Kevin

The For/In loop, simply loops through all properties in an object. Since you are not specifying the number of iterations the loop needs to take, it simply 'guesses' at it, and continues on until there are no more objects.

For/In 循环,只是循环遍历对象中的所有属性。由于您没有指定循环需要进行的迭代次数,它只是对其进行“猜测”,然后继续直到没有更多对象为止。

With the second loop, you are specifying all possible variable... a)a starting point, b) the number of iterations the loop should take before stopping, c) increasing the count of the starting point.

在第二个循环中,您指定所有可能的变量... a)a 起点,b) 循环停止前应进行的迭代次数,c) 增加起点的计数。

You can think of it this way... For/In = guesses the number of iterations, For(a,b,c) you are specifying

你可以这样想... For/In = 猜测迭代次数,你指定的 For(a,b,c)