Javascript的优化建议

时间:2009-08-23 07:08:42

标签: javascript optimization

鉴于此代码:

    var minX = minY = maxX = maxY = 0;

    for(var i=0; i<objArray.length; i++){
        if(objArray[i].x < minX){
            minX = objArray[i].x;
        }else if(objArray [i].x > maxX){
            maxX = objArray[i].x;
        }
        if(objArray[i].y < minY){
            minY = objArray[i].y;
        }else if(objArray [i].y > maxY){
            maxY = objArray[i].y;
        }
    }

它有效,但我认为它不是很优雅。 它是简单的逻辑,但它使用10行代码。可以改进吗?

3 个答案:

答案 0 :(得分:10)

您可以使用Math.minMath.max

var minX = minY = Number.POSITIVE_INFINITY,
    maxX = maxY = Number.NEGATIVE_INFINITY;

for(var i=0; i<objArray.length; i++){
  minX = Math.min(objArray[i].x, minX);
  minY = Math.min(objArray[i].y, minY);
  maxX = Math.max(objArray[i].x, maxX);
  maxY = Math.max(objArray[i].y, maxY);
}

对于循环速度优化,您可以将长度存储为仅计算一次:

for(var i=0, len = objArray.length; i<len; i++){
  //...
}

检查此article以获取有关循环优化的更多信息。

另一种方法,仅仅是为了“功能性乐趣”,因为我不推荐它的性能,可能是使用Array.map将x和y值分成两个数组,并且然后使用apply调用最小和最大函数:

var allX = objArray.map(function (o) { return o.x; });
var allY = objArray.map(function (o) { return o.y; });

minX = Math.min.apply(Math, allX);
minY = Math.min.apply(Math, allY);
maxX = Math.max.apply(Math, allX);
maxY = Math.max.apply(Math, allY);

这是如何运作的?

apply函数用于调用具有给定上下文和参数的另一个函数,作为数组提供。 min和max函数可以使用任意数量的输入参数:Math.max(val1,val2,...,valN)

所以如果我们打电话:

Math.min.apply(Math, [1,2,3,4]);

apply函数将执行:

Math.min(1,2,3,4);

请注意,第一个参数(上下文)对于这些函数并不重要,因为它们是静态的,无论作为上下文传递什么,它们都将起作用。

答案 1 :(得分:5)

  

它最多使用10行代码。

但是,LoC不是优化的衡量标准。

我在Firefox 3.5中测试了上述算法。 (有关测试用例,请参见下文。)

您的原始代码(methodA)几乎是CMS(methodB)的两倍! Math.min的使用使他的版本更具可读性,并且在大多数情况下这是重要的。但它确实引入了更多的查找和函数调用,这会减慢它的速度。

'功能性乐趣'版本(methodC)实际上比任何一个版本快得多!这对我来说是一个惊喜,因为这个版本必须构建两个临时数组,但似乎很好地使用apply()来一次性完成所有比较,弥补了这一点。但是,这是在Firefox上,其中有一个Array.map()的本机实现。没有此功能的IE浏览器需要将JavaScript版本入侵到Array原型中,这使得methodC对于我来说就像方法B一样慢。

正如预期的那样,史蒂思的替代功能版本非常缓慢;所有这些临时物品都会造成损失。

最后我管理的最快的是采用原始方法A并调整它以删除每循环.length访问,并微观优化多个属性访问。令人惊讶的是,这个(方法E)敲了一下。

但是,所有这些通常都是特定于浏览器的。我只在一个浏览器上测试过;你可能会对别人有不同的结果。通常微优化不会得到回报,你最好选择最易读的选项。

<script type="text/javascript">
    var objArray= [];
    for (var i= 0; i<1000000; i++) {
        objArray.push({'x': Math.floor(Math.random()*100000), 'y': Math.floor(Math.random()*100000)});
    }

    function methodA() {
        var t= new Date();
        var minX = minY = maxX = maxY = 0;
        for(var i=0; i<objArray.length; i++){
                if(objArray[i].x < minX){
                        minX = objArray[i].x;
                }else if(objArray [i].x > maxX){
                        maxX = objArray[i].x;
                }
                if(objArray[i].y < minY){
                        minY = objArray[i].y;
                }else if(objArray [i].y > maxY){
                        maxY = objArray[i].y;
                }
        }
        alert(new Date()-t);
    }
    function methodB() {
        var t= new Date();
        var minX = minY = Number.POSITIVE_INFINITY,
            maxX = maxY = Number.NEGATIVE_INFINITY;
        for(var i=0; i<objArray.length; i++){
          minX = Math.min(objArray[i].x, minX);
          minY = Math.min(objArray[i].y, minY);
          maxX = Math.max(objArray[i].x, maxX);
          maxY = Math.max(objArray[i].y, maxY);
        }
        alert(new Date()-t);
    }
    function methodC() {
        var t= new Date();
        var allX = objArray.map(function (o) { return o.x; });
        var allY = objArray.map(function (o) { return o.y; });

        minX = Math.min.apply(Math, allX);
        minY = Math.min.apply(Math, allY);
        maxX = Math.max.apply(Math, allX);
        maxY = Math.max.apply(Math, allY);
        alert(new Date()-t);
    }
    function methodD() {
        var t= new Date();
        var minX = objArray.reduce( function(a,b) { return {x : Math.min(a.x,b.x)};}).x;
        var minY = objArray.reduce( function(a,b) { return {y : Math.min(a.y,b.y)};}).y;
        var maxX = objArray.reduce( function(a,b) { return {x : Math.max(a.x,b.x)};}).x;
        var maxY = objArray.reduce( function(a,b) { return {y : Math.max(a.y,b.y)};}).y;
        alert(new Date()-t);
    }
    function methodE() {
        var t= new Date();
        var minX = minY = maxX = maxY = 0;
        var o, v;
        for (var i=objArray.length; i-->0;) {
            o= objArray[i];
            v= o.x;
            if (v<minX) minX= v;
            if (v>maxX) maxX= v;
            v= o.y;
            if (v<minY) minY= v;
            if (v>maxY) maxY= v;
        }
        alert(new Date()-t);
    }
</script>
<button onclick="methodA()">A</button>
<button onclick="methodB()">B</button>
<button onclick="methodC()">C</button>
<button onclick="methodD()">D</button>
<button onclick="methodE()">E</button>

答案 2 :(得分:1)

到目前为止,所有答案似乎都是在比较中使用未初始化的变量(minX等)。这是一个功能强大,优雅的解决方案:

var minX = anarray.reduce( function(a,b) { return {x : Math.min(a.x,b.x)};}).x;
var minY = anarray.reduce( function(a,b) { return {y : Math.min(a.y,b.y)};}).y;
var maxX = anarray.reduce( function(a,b) { return {x : Math.max(a.x,b.x)};}).x;
var maxY = anarray.reduce( function(a,b) { return {y : Math.max(a.y,b.y)};}).y;

查看here以获取有关reduce函数的说明以及如何在本机不支持它的浏览器中启用它。