2008-10-11 7 views
28

J'ai trébuché en plusieurs méthodes de bouclage en JavaScript, ce que j'aime le plus est:Quelle est la meilleure façon de faire des boucles en JavaScript

for(var i = 0; i < a.length; i++){ 
    var element = a[i]; 
} 

Mais testé ici (http://www.robertnyman.com/2008/04/11/javascript-loop-performance/), il devrait probablement être écrit de sorte que la longueur ne soit calculée qu'une seule fois.

Dans jQuery, il existe un .each permettant de coller une fonction. J'aime un peu mieux, car je n'ai pas à taper deux fois le tableau, comme dans la solution ci-dessus.

Si les macros JavaScript sont supportées, ce serait un jeu d'enfant de rouler le vôtre, mais ce n'est malheureusement pas le cas.

Alors qu'est-ce que vous utilisez?

+0

Apparemment, ce que vous entendez par «meilleur» est «plus propre», n'est-ce pas? Certains pourraient dire que la "meilleure" manière est de le faire quelle que soit la manière la plus rapide, auquel cas la réponse est probablement différente ... –

+0

Ouais bien. J'ai choisi le mot le mieux, parce que je voulais une solution en boucle que je puisse toujours utiliser sans vraiment y penser.Donc ça ne doit pas être horriblement lent quand on court sur 100k éléments, ça ne doit pas être horriblement long à écrire etc –

Répondre

36

J'ai commencé à utiliser des itérateurs, le cas échéant. La performance est raisonnable, mais plus important encore, il vous permet d'encapsuler la logique en boucle:

function createIterator(x) { 
    var i = 0; 

    return function(){ 
     return x[i++]; 
    }; 
} 

ensuite à utiliser:

var iterator=createIterator(['a','b','c','d','e','f','g']); 

iterator(); 

renvoie "un";

iterator(); 

renvoie "b";

et ainsi de suite.

Pour itérer la liste complète et afficher chaque élément:

 
var current; 

while(current=iterator()) 
{ 
    console.log(current); 
} 

Notez que le modèle est au-dessus acceptable pour itérer une liste qui contient des valeurs « non falsy ». Si ce tableau contenait une de:

  • faux
  • ""
  • null
  • NaN

la boucle précédente s'arrêterait à cet article, pas toujours ce que vous vouloir/attendre.

Pour éviter cette utilisation:

var current; 

while((current=iterator())!==undefined) 
{ 
    console.log(current); 
} 
+0

Ouais, j'ai aussi pensé à utiliser des itérateurs. Ils encapsulent mieux le concept de traverser quelque chose que de simples boucles. Mais comment voulez-vous dans votre exemple imprimer tous les éléments de l'itérateur? –

+0

Belle fermeture douceur. Ahh, je les aime. –

+0

Comment savez-vous quand vous avez atteint la fin si votre itérateur n'a pas une fonction HasNext? Si vous continuez à appeler "itérateur" selon votre exemple, vous finirez par obtenir un index de tableau hors limites. – Kibbee

2

Vous pouvez toujours utiliser une boucle while et calculer la limite du tableau avant la main.

Var max = a.length-1; 
var i = 0; 

while(i <= max) 
{ 
var element = a[i]; 
i++; 
} 
+0

Désolé d'être franc, mais je ne vois pas en quoi c'est une amélioration. Vous spécifiez toujours le tableau deux fois, et dans votre solution l'environnement autour est pollué avec deux variables qui ne doivent pas transcoder la construction de la boucle while. –

+0

L'environnement va quand même être "pollué", étant donné qu'en Javascript la portée d'une variable est la fonction englobante, pas le bloc dans lequel elle est déclarée. –

+0

En le testant par rapport au lien donné dans la question, il est au moins aussi rapide, sinon plus rapide, que n'importe quelle implémentation de la boucle for. – Kibbee

9

Petite amélioration à l'original, pour calculer seulement la taille du tableau une fois:

for(var i = 0, len = a.length; i < len; i++){ var element = a[i]; } 

Aussi, je vois beaucoup de boucles for..in. Bien garder à l'esprit que ce n'est pas techniquement casher, et cause des problèmes avec Prototype spécifiquement:

for (i in a) { var element = a[i]; } 
+1

for..in boucles sont utilisées pour itérer sur les propriétés de l'objet, alors qu'ils semblent fonctionner pour les tableaux, ils vont également itérer sur la propriété 'length' ou tout autre dynamiquement propriété ajoutée. C'est pourquoi cela ne fonctionne pas bien avec Prototype. –

+1

le deuxième exemple «i» est probablement en train de créer un – ajax333221

6

magasin juste la longueur dans une première variable.

var len = a.length; 
    for (var i = 0; i < len; i++) { 
    var element = a[i]; 
    } 
1

Si vous avez plusieurs éléments dans la matrice et que la vitesse est un problème, alors vous voulez utiliser une boucle while qui va du plus haut au plus bas.

var i = a.length; 
    while(--i >= 0) { 
    var element = a[i]; 
    // do stuff with element 
    } 
+0

global le> = 0 n'est pas nécessaire, il suffit de changer - i à i-- –

1

Je ne l'utilise pas moi-même, mais un de mes collègues utilise ce style:

var myArray = [1,2,3,4]; 
for (var i = 0, item; item = myArray[i]; ++i) { 
    alert(item); 
} 

comme la réponse de Ash, cela frappera des problèmes si vous avez des valeurs « Falsey » dans votre tableau. Pour éviter ce problème, changez-le en (item = myArray[i]) != undefined

6

Je sais que je suis en retard à la fête, mais j'utilise des boucles inversées pour les boucles qui ne dépendent pas de l'ordre.

Très similaire à @Mr. Muskrat de - mais qui simplifie le test:

var i = a.length, element = null; 
while (i--) { 
    element = a[i]; 
} 
+0

et je suis * très * en retard à la fête, mais c'est la bonne réponse et devrait être accepté en tant que tel. Pour les non-initiés, la clause i-save sauvegarde une comparaison (car 0 = faux dans les tests JS). Avertissement 1: ordre inverse! Avertissement 2: la lisibilité n'est pas géniale. Mise en garde 3: une boucle pour la boucle est presque aussi bonne – annakata

-2

Alors, d'abord vous identifier la boucle javascript parfaite, je crois qu'il devrait ressembler à ceci:

ary.each (function() {$ arguments [0]) .remove();})

Cela peut nécessiter la bibliothèque prototype.js.

Ensuite, vous obtenez dégoût avec la partie arguments [0] et que le code soit produit automatiquement à partir de votre infrastructure de serveur. Cela ne fonctionne que si l'échelle est Seaside.

Maintenant, vous avez ci-dessus généré par:

do Ary: [: each | chaque élément est supprimé].

Ceci est livré avec l'achèvement de la syntaxe et traduit exactement au javascript ci-dessus. Et cela fera tourner la tête aux gens qui n'ont jamais utilisé l'intégration de prototypes de bord de mer, alors qu'ils lisent votre code. C'est sûr que tu te sens cool aussi. Sans parler du gain de geek que vous pouvez obtenir ici. Les filles adorent ça!

0

Je ne vois pas quel est le problème avec l'utilisation d'un standard pour la boucle (;;). Un petit test

var x; 
var a = []; 
// filling array 
var t0 = new Date().getTime(); 
for(var i = 0; i < 100000; i++) { 
    a[i] = Math.floor(Math.random()*100000); 
} 

// normal loop 
var t1 = new Date().getTime(); 
for(var i = 0; i < 100000; i++) { 
    x = a[i]; 
} 

// using length 
var t2 = new Date().getTime(); 
for(var i = 0; i < a.length; i++) { 
    x = a[i]; 
} 

// storing length (pollution - we now have a global l as well as an i) 
var t3 = new Date().getTime(); 
for(var i = 0, l = a.length; i < l; i++) { 
    x = a[i]; 
} 

// for in 
var t4 = new Date().getTime(); 
for(var i in a) { 
    x = a[i]; 
} 

// checked for in 
var t5 = new Date().getTime(); 
for(var i in a) { 
    if (a.hasOwnProperty(i)) { 
     x = a[i]; 
    } 
} 

var t6 = new Date().getTime(); 
var msg = 'filling array: '+(t1-t0)+'ms\n'+ 
      'normal loop: '+(t2-t1)+'ms\n'+ 
      'using length: '+(t3-t2)+'ms\n'+ 
      'storing length: '+(t4-t3)+'ms\n'+ 
      'for in: '+(t5-t4)+'ms\n'+ 
      'checked for in: '+(t6-t5)+'ms'; 
console.log(msg); 

résultats dans:

filling array: 227ms 
normal loop: 21ms 
using length: 26ms 
storing length: 24ms 
for in: 154ms 
checked for in: 176ms 

Ainsi: - dans ce sont les plus longs, en utilisant la propriété de longueur (ce qui est une propriété et n'a pas besoin d'être calculé) est presque aussi vite que le stocker en premier - ce qui n'est qu'un moustache plus lent que l'utilisation d'un nombre entier.
ET un pour() est la manière habituelle de faire une boucle sur un tableau, ce que tout le monde attend et comprend. Tous ajoutent une variable à la portée dans laquelle ils s'exécutent - i - qui est un nom commun pour cette utilisation et ne devrait donc pas être utilisé pour d'autres choses. Stocker la longueur en premier ajoute un autre var - l - à la portée, ce qui n'est pas nécessaire