2010-10-16 5 views
13

Folgende Arbeiten wie erwartet:Warum gibt es keine jQuery-Objekte, wenn ich über jQuery-Objekte mit .each() iteriere?

$(".foo").first().text("hi!") 

... weil first() kehrt ein Objekt jQuery.

Allerdings, wenn ich mit der text() Methode für alle Spiele arbeiten will, muß ich tun:

$(".foo").each(function(idx, obj) { 
    $(obj).text("hi!") 
    } 
) 

... weil each() geben Sie Objekte DOM.

Was ist der Designgrund für diesen verwirrenden Unterschied? Wie kann ich vermeiden, ein jQuery-Objekt für jede Übereinstimmung zu erstellen?

Antwort

11

Möglicherweise aus Performance-Gründen im Zusammenhang mit Schleifen über große Sammlungen? Wenn Sie nur die DOM-Objekte benötigen, dann speichern Sie Zyklen. Wenn Sie das jQuery-Objekt benötigen, können Sie das leicht erreichen.

Ich gebe normalerweise nicht den 2. Parameter, also kann ich $ (this) verwenden.

+0

Genau das, was ich sagen wollte, und wenn first() kein jQuery-Objekt zurückgegeben hat, müssten Sie $ ($ (selector) .first()) verwenden, was etwas mit jQuerys Ziel kollidiert. –

+0

Okay, ich hatte den Eindruck, dass '$ (". Foo ")' jQuery-Objekte _mit _ beginnen ließ und sie zu "einfachen" DOM-Objekten zerlegt wurden, wenn sie durch 'each()' übergeben wurden. Ich denke, das ist nicht ganz das, was hier passiert :) – badp

+0

@Jon - Das ist nicht korrekt. '$ (selector) .first()' * gibt * ein jQuery-Objekt zurück. Sie sollten es nicht erneut mit '$ ($ (selector) .first())' umbrechen. Die einzige jQuery-Methode (nach meinem Wissen), die ein einfaches DOM-Element zurückgibt, ist '.get (0)', wenn Sie eine Zahl übergeben. Ohne das Zahl-Argument erhalten Sie ein Array von DOM-Elementen. – user113716

0

Sahen Sie .each vs jQuery.each

Sie sollten in der Lage, Folgendes zu tun:

$('li').each(function(index) { 
    alert(index + ': ' + $(this).text()); 
}); 

pro den ersten Link. Versuchen Sie $(this) statt $(obj)

+0

Dies ist in keiner sinnvollen Weise anders. Ich muss noch jQuery-Objekte erstellen. – badp

0

versuchen

$(".foo").each(function(idx, obj) { 
    $(this).text("hi!") 
    } 
) 
+0

Der '$()' Konstruktor ist immer noch da. – badp

0

Ich glaube, dass, da jQuery Wrapper-Objekte verwendet, die erste Methode den ursprünglichen Wrapper verwendet und nur alle außer dem ersten Element im Wrapper entfernt, so dass es ein jQuery-Objekt bleibt.

Wenn sie jedoch ein jQuery-Objekt für jeden der Knoten für die each()-Funktion einspeisen würden, würden sie diesen Mehraufwand für die Erstellung des Wrappers für jeden einzelnen erzeugen. Und da Sie das Wrapper-Objekt nicht unbedingt benötigen, würde dies unnötigen Overhead verursachen.

1

Intern jQuery nennen dies für $("sel").each(function(){});

if (isObj) { 
    for (name in object) { 
     if (callback.call(object[ name ], name, object[ name ]) === false) { 
      break; 
     } 
    } 
} 

Und die eq ist eine einfache Scheibe:

eq: function(i) { 
    return i === -1 ? 
    this.slice(i) : 
    this.slice(i, +i + 1); 
} 

So können Sie eine neue each Funktion erstellen, die anstelle von object[name] eine object:eq(i)

tun
$("*").slice(1,2).toSource() == $("*").eq(1).toSource(); 

So eigene erstellen each:

$.fn.each2 = function(callback) 
{ 
    for (var i = 0; i < this.length; ++i) { 
     callback.call(this.eq(i), i, this.eq(i)) 
    } 
}; 

$("*").each2(function(i, obj) { 
    alert(obj); // now obj is a jQuery object 
}); 

Es scheint, dass each3 schneller als each2http://www.jsfiddle.net/m7pKk/2/

$.fn.each2 = function(callback) 
{ 
    for (var i = 0; i < this.length; ++i) { 
     var jObj = this.eq(i); 
     callback.call(jObj, i, jObj) 
    } 
}; 

$.fn.each3 = function(callback) 
{ 
    for (var i = 0; i < this.length; ++i) { 
     var jObj = $(this[i]); 
     callback.call(jObj, i, jObj) 
    } 
}; 

See this example on jsFiddle with performance measurement.

+0

Also [dies] (http://gist.github.com/629941) würde auch funktionieren? :) Außerdem muss ich jetzt ein Profiling durchführen, um zu verstehen, was schneller ist. – badp

+0

@ badp: Ja. Ich denke nicht, dass es auf 'obj [i] 'und' obj.slice (i, i + 1)' viel Unterschied gibt ... Siehe das Beispiel hier http://www.jsfiddle.net/m7pKk/ – BrunoLM

+0

@ BrunoLM, eigentlich '$ (". Foo ") [i]' gibt ein DOM-Objekt zurück, während '$ (". Foo "). Eq (i)' gibt ein jQuery-Objekt. Das ist ziemlich genau der Punkt hier, und angesichts der Implementierung von 'eq' durch Slices bin ich fast zu der Überzeugung gelangt, dass' $ ($ (". Foo") [i]) 'schneller wäre ... – badp

1

Es ist die offensichtliche Performance-Hit ist, dass sein würde genommen pro Iteration. Das Erstellen eines neuen jQuery-Objekts würde bei jeder Iteration viel langsamer und wahrscheinlich bei großen Sammlungen wahrnehmbar sein. Häufig benötigen Sie den zusätzlichen Komfort des umschlossenen Objekts nicht, insbesondere nicht beim Zugriff auf einzelne Attribute oder Eigenschaften. Allzu oft sehen Sie Zyklusverschwendungscode wie $(this).is(":checked") anstelle von this.checked.

Abgesehen davon, würde ich sagen, dass es ist, weil es Sinn macht. Ein jQuery-Objekt repräsentiert normalerweise eine Sammlung von DOM-Objekten, deren Größe beliebig sein kann. Manchmal wird jQuery nur für die Selektorunterstützung und die Ereignisbindung verwendet und nicht viel darüber hinaus. Es macht wenig Sinn, eine Sammlung zurückzugeben, die ein einzelnes Element enthält, wenn man über eine Sammlung von mehr Elementen iteriert. Es macht viel mehr Sinn, ein einzelnes Element, das Sie wahrscheinlich benötigen, das DOM-Element zurückzugeben, dann können Sie es mit jQuery umschließen, wenn Sie die hinzugefügten Funktionen benötigen. Dies hält es auch in Einklang mit der Iteration über NodeList und andere Arten der Sammlung.

0

Wahrscheinlich, weil es in Ihrem Beispiel keinen Grund gibt, each zu verwenden. Statt:

$(".foo").each(function(idx, obj) { 
    $(obj).text("hi!"); 
) 

Verwenden Sie einfach:

$(".foo").text("hi!"); 

Alles automatisch Plural ist, wenn mit jQuery-Sets zu tun.

+1

Ich muss eine Funktion pro Treffer aufrufen, die komplizierter ist als nur ein '.text()' Aufruf :) – badp

+0

Aber das wird richtig zu dem Problem - wenn Sie etwas für jedes Element im Set einzigartig machen müssen macht es überhaupt Sinn, sie alle zusammen mit ".foo" auszuwählen? – jpsimons

+0

ja, wenn ich sagen möchte, eine mathematische Funktion auf den Wert in jedem ".foo" anzuwenden. Gleiche Funktion, unterschiedliche Eingabe, unterschiedliche Ausgabe. – badp

Verwandte Themen