2010-10-16 11 views
13

I seguenti lavori come previsto:Perché iterare su oggetti jQuery con .each() non mi fornisce oggetti jQuery?

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

... perché first() restituisce un oggetto jQuery.

Tuttavia, se voglio lavorare con il metodo text() per tutte le partite, ho bisogno di fare:

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

... perché ti dà each() oggetti DOM.

Qual è la ragione di progettazione dietro questa sconcertante differenza? Come posso evitare di dover creare un oggetto jQuery per ogni abbinamento?

risposta

11

Forse a causa di motivi di prestazioni relative al ciclo su grandi collezioni? Se hai solo bisogno degli oggetti DOM, allora salvi i cicli. Se ti serve l'oggetto jQuery, puoi facilmente ottenerlo.

In genere non fornisco il 2 ° parametro a ciascuno, quindi posso utilizzare $ (questo).

+0

Esattamente quello che stavo per dire, più se first() non restituisce un oggetto jQuery, dovresti usare $ ($ (selector) .first()), che in qualche modo è in conflitto con l'obiettivo di jQuery di essere conciso. –

+0

Ok, ho avuto l'impressione che '$ (". Foo ")' abbia creato oggetti jQuery _to per cominciare con _ e sono stati rimossi dagli oggetti DOM "di base" quando sono passati attraverso 'each()'. Immagino che non sia proprio quello che succede qui :) – badp

+0

@ Jon - Non è corretto. '$ (selettore) .first()' * fa * restituisce un oggetto jQuery. Non dovresti riavvolgerlo di nuovo con '$ ($ (selettore) .first())'. L'unico metodo jQuery (a mia conoscenza) che restituisce un semplice elemento DOM è '.get (0)' quando si passa un numero. Senza l'argomento numero, ottieni una matrice di elementi DOM. – user113716

0

Hai visto .each vs jQuery.each

Si dovrebbe essere in grado di effettuare le seguenti operazioni:

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

per il primo collegamento. Prova $(this) invece di $(obj)

+0

Questo non è in modo significativo diverso. Devo ancora creare oggetti jQuery. – badp

0

Prova

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

Il costruttore '$()' è ancora lì. – badp

0

Credo che dal momento che jQuery utilizza gli oggetti wrapper, il primo metodo utilizza il wrapper originale e rimuove tutto tranne il primo elemento nel wrapper, mantenendolo quindi come un oggetto jQuery.

Tuttavia, se fossero ad alimentare in un oggetto jQuery per ciascuno dei nodi per la funzione each(), sarebbero incorrere che sovraccarico di creare l'involucro per ciascuno. E dal momento che non vuoi necessariamente quell'oggetto wrapper, ciò comporterebbe un sovraccarico non necessario.

1

Internamente jQuery chiamare questo per $("sel").each(function(){});

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

E il eq è una fetta semplice:

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

Così si può creare una nuova each funzione che invece di object[name] farà un object:eq(i)

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

Quindi, per creare il proprio 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 
}); 

Sembra che each3 è più veloce di 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

Quindi [questo] (http://gist.github.com/629941) funzionerebbe pure? :) Inoltre ora ho bisogno di fare un po 'di profilazione per capire qual è il più veloce. – badp

+0

@badp: Sì. Non penso che ci sia molta differenza su 'obj [i]' e 'obj.slice (i, i + 1)' ... Vedi l'esempio qui http://www.jsfiddle.net/m7pKk/ – BrunoLM

+0

@ BrunoLM, in realtà '$ (". Foo ") [i]' restituisce un oggetto DOM mentre '$ (". Foo "). Eq (i)' fornisce un oggetto jQuery. Il punto è questo, e visto l'implementazione di 'eq' attraverso le slice sono quasi indotto a credere che' $ ($ (". Foo") [i]) 'sarebbe più veloce ... – badp

1

C'è il colpo ovvio prestazioni che sarebbe prese per iterazione. La creazione di un nuovo oggetto jQuery ogni iterazione sarebbe molto più lenta e probabilmente rilevabile su raccolte di grandi dimensioni. Molto spesso, non è necessaria la comodità aggiuntiva dell'oggetto avvolto, specialmente quando si accede a singoli attributi o proprietà. Troppo spesso si vede codice sprecare ciclo come $(this).is(":checked") invece di this.checked.

A parte questo, tuttavia, direi che è perché ha senso. Un oggetto jQuery rappresenta in genere una raccolta di oggetti DOM che può avere un numero qualsiasi di dimensioni. Talvolta jQuery viene utilizzato esclusivamente per il suo supporto per i selettori e per l'associazione degli eventi e non molto oltre. Non ha molto senso restituire una raccolta contenente un singolo elemento durante l'iterazione su una raccolta di più elementi. Ha molto più senso restituire un singolo elemento di cui è più probabile che sia necessario, l'elemento DOM, quindi puoi aggiungerlo con jQuery se desideri le funzionalità aggiunte. Questo inoltre lo mantiene in linea con l'iterazione su NodeList e altri tipi di raccolta.

0

Probabilmente perché, nel tuo esempio, non c'è motivo di utilizzare anche each. Invece di:

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

Basta usare:

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

Tutto è automaticamente plurale quando si tratta di set di jQuery.

+1

Avrò bisogno di chiamare una funzione per hit che è più complicata di una chiamata '.text()' :) – badp

+0

Ma questo giunge al problema - se devi fare qualcosa di unico per ogni oggetto nel set , ha senso anche selezionarli tutti insieme a ".foo"? – jpsimons

+0

sì, se voglio, diciamo, applicare una funzione matematica al valore di ogni ".foo". Stessa funzione, input diversi, output differente. – badp