2009-08-23 9 views
2

Étant donné ce code:Suggestions d'optimisation Javascript pour

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; 
     } 
    } 

Il fonctionne, mais je ne pense pas que ce soit très élégant. C'est une logique simple, mais elle utilise 10 lignes de code. Peut-il être amélioré?

Répondre

10

Vous pouvez utiliser Math.min et Math.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); 
} 

Pour l'optimisation de la vitesse de la boucle, vous pouvez stocker la longueur seulement calculer une fois:

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

Cocher cette article pour plus d'informations sur l'optimisation des boucles.

Une autre approche, juste pour le « plaisir fonctionnel », car je ne le recommanderais pas pour la performance, pourrait être de séparer les valeurs de x et y à deux tableaux en utilisant Array.map, puis appeler les fonctions min et max avec 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); 

Comment ça marche?

La fonction apply permet d'appeler une autre fonction, avec un contexte et des arguments donnés, sous forme de tableau. Les fonctions min et max peuvent prendre un nombre arbitraire d'arguments d'entrée: Math.max (val1, val2, ..., Valn)

Donc, si nous appelons:

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

La fonction de transformation s'exécutera:

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

Notez que le premier paramètre, le contexte, n'a pas d'importance pour ces fonctions car ils sont statiques, ils fonctionneront indépendamment de ce qui est passé comme contexte.

+0

besoin d'une autre édition en ce moment - encore, bon travail. –

+0

@Andy: Edité, merci! – CMS

1

Toutes les réponses semblent jusqu'à présent utiliser des variables non initialisées (minX, etc.) dans les comparaisons. Voici une solution fonctionnelle, élégante:

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; 

Rechercher here pour une explication de la diminution de la fonction et comment activer dans les navigateurs qui ne prennent pas en charge en mode natif.

5

il utilise jusqu'à 10 lignes de code.

Cependant, le LoC n'est pas une mesure de optimisation.

J'ai testé les algorithmes ci-dessus dans Firefox 3.5. (Voir ci-dessous pour le cas de test.)

Votre code original (méthodeA) était presque deux fois plus rapide que celui du CMS (méthodeB)! L'utilisation de Math.min rend sa version beaucoup plus lisible, et dans la plupart des cas c'est ce qui est important. Mais cela introduit plus de recherches et d'appels de fonctions, et cela le ralentit.

La version 'fun' fonctionnelle (methodC) était en réalité considérablement plus rapide que n'importe quelle version! Cela a été une surprise pour moi puisque cette version doit construire deux tableaux temporaires, mais il semble que la bonne utilisation de apply() pour faire toutes les comparaisons en une fois compense cela. C'est, cependant, sur Firefox, où il y a une implémentation native de Array.map(). Les navigateurs comme IE qui ne disposent pas de cette fonctionnalité nécessitent de pirater une version JavaScript dans le prototype Array, ce qui a rendu methodC aussi lent que methodB pour moi.

La version fonctionnelle alternative de Steveth était, comme prévu, très lente; tous ces objets temporaires prennent un péage. En fin de compte, le plus rapide que j'ai géré était de prendre la méthode originale A et de l'ajuster pour supprimer l'accès à la longueur par boucle, et micro-optimiser les multiples accès aux propriétés. Étonnamment, cette méthode a été un peu déstabilisée.

Cependant, tout ceci est généralement très spécifique au navigateur. J'ai seulement testé sur un navigateur; vous pouvez obtenir des résultats différents sur les autres. Habituellement, la micro-optimisation ne rapporte pas et il vaut mieux choisir l'option la plus lisible.

<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> 
+0

Très bon résumé des caractéristiques de performance de ce code - et l'inutilité de s'en remettre trop fortement! –

Questions connexes