2012-05-24 3 views
11

ich auf Javascript lesen: The Good Parts ...JQuery und Underscore "each" garantiert Reihenfolge für ein Array?

Da JavaScript die Arrays wirklich sind Objekte, die for in Anweisung kann alle Eigenschaften eines Arrays iterieren verwendet werden. Leider, denn über die Reihenfolge der Eigenschaften keine Garantie macht ...

Soweit ich die „jeweils“ Funktionen kennen for in basieren, dann tut each Funktion Form JQuery und Bibliotheken Unders Ordnung garantieren, wenn sie über ein Array iterieren? Ich versuche, den lästigen Standard for zu vermeiden.

Vielen Dank im Voraus.

+1

Stellen Sie sicher, dass Sie wissen, was ein Array ist und was ein Objekt in JavaScript ist ... – Pointy

Antwort

16

Bei der Iteration durch ein Array ist die Reihenfolge immer garantiert. Es ist, wenn Sie durch (Nicht-Array-) Objekte iterieren, wenn es keine Garantie gibt. Arrays sind übrigens noch Objekte.


each ist nicht mehr als ein for in für Objekte und for für Array-like. Das Framework bestimmt die richtige Schleife für den Job, und es gilt die gleiche Logik: Array-Iterationen sind geordnet, während die Objektiteration nicht korrekt ist.

Unders der Quelle:

var each = _.each = _.forEach = function (obj, iterator, context) { 
     if (obj == null) return; 
     if (nativeForEach && obj.forEach === nativeForEach) { 
      obj.forEach(iterator, context); 
     } else if (obj.length === +obj.length) { 
      for (var i = 0, l = obj.length; i < l; i++) { 
       if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; 
      } 
     } else { 
      for (var key in obj) { 
       if (_.has(obj, key)) { 
        if (iterator.call(context, obj[key], key, obj) === breaker) return; 
       } 
      } 
     } 
    }; 

jQuery Quelle:

each: function (object, callback, args) { 
    var name, i = 0, 
     length = object.length, 
     isObj = length === undefined || jQuery.isFunction(object); 
    if (args) { 
     if (isObj) { 
      for (name in object) { 
       if (callback.apply(object[name], args) === false) { 
        break; 
       } 
      } 
     } else { 
      for (; i < length;) { 
       if (callback.apply(object[i++], args) === false) { 
        break; 
       } 
      } 
     } 
     // A special, fast, case for the most common use of each 
    } else { 
     if (isObj) { 
      for (name in object) { 
       if (callback.call(object[name], name, object[name]) === false) { 
        break; 
       } 
      } 
     } else { 
      for (; i < length;) { 
       if (callback.call(object[i], i, object[i++]) === false) { 
        break; 
       } 
      } 
     } 
    } 
    return object; 
} 
+0

Ich habe die Frage bearbeitet, weil ich denke, dass es nicht klar war. Ich mache mir mehr Gedanken um die Funktionen als um das Thema Objekte/Arrays. – davidgnin

+0

@davidgnin ist jeweils nichts mehr als 'for' und' for in' loops. Die gleiche Logik gilt. – Joseph

+0

Danke! Dann in Arrays ist jeder für, nicht für in. Das war genau das, was ich versuchte zu wissen. – davidgnin

3

Es gibt zwei Möglichkeiten, können Sie eine Schleife über ein Array: eine numerische Schleife über die indizierten Elemente eines Arrays oder ein for in Schleife über die Objekteigenschaften eines Arrays.

var a = ['a','b']; 
a[3] = 'e'; 
a[2] = 'd'; 
a.foo = function() { }; 
for(key in a) 
    console.log(key); 

Das gibt 0 1 3 2 foo, da, dass die Reihenfolge ist die Eigenschaften definiert wurden (aber es gibt kein Versprechen, dass Ihr Browser muss auch dieses Verhalten zeigen, entweder).

Bisher sehen numerische Schleifen besser aus, aber sie können keine Ersatzarrays, d. H. Arrays mit Lücken, handhaben. Die ES5 Array.forEach lässt nicht spezifizierte Werte aus, während $.each von jQuery eine numerische Schleife verwendet, die auf der length-Eigenschaft basiert.

var a = [1,2]; 
a[1000000] = 4; 
a[9000] = 3; 
a.foo = function() {}; 

// outputs 0, 1, 9000, 1000000 -- note they are in order 
a.forEach(function(elem, index){ console.log(index); }) 

// outputs 0, 1, 9000, 1000000 -- same as above 
_.each(a, function(elem, index){ console.log(index); }) 

// outputs a million values and locks up your browser for a while 
$.each(a, function(index){ console.log(index); }) 

Also, beide forEach und $.each Ihre Werte in Index-Reihenfolge zurück, aber forEach und Unders scheinen überlegen für spärlichen Arrays, da sie Indizes ignorieren, die keinen Wert zugewiesen hatten.