2010-10-16 16 views
13

las siguientes obras: como se esperaba¿Por qué la iteración sobre objetos jQuery con .each() no me da objetos jQuery?

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

... porque first() devuelve un objeto jQuery.

Sin embargo, si quiero trabajar con el método text() para todos los partidos, que tengo que hacer:

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

... porque te da each() objetos DOM.

¿Cuál es el motivo del diseño detrás de esta desconcertante diferencia? ¿Cómo puedo evitar tener que crear un objeto jQuery para cada coincidencia?

Respuesta

11

Posiblemente debido a problemas de rendimiento relacionados con el bucle más grandes colecciones? Si solo necesita los objetos DOM, entonces guarda ciclos. Si necesita el objeto jQuery, puede obtenerlo fácilmente.

Normalmente no proporciono el 2º parámetro para cada uno, así que puedo usar $ (esto).

+0

Exactamente lo que iba a decir, más si first() no devolvió un objeto jQuery, tendría que usar $ ($ (selector) .first()), lo que de alguna manera entra en conflicto con el objetivo de jQuery de ser conciso. –

+0

De acuerdo, tenía la impresión de que '$ (". Foo ")' hacía que los objetos jQuery _comienzaran_ y que se desglosaran en objetos DOM "básicos" cuando pasaban por 'each()'. Supongo que no es exactamente lo que está pasando aquí :) – badp

+0

@Jon - Eso no es correcto. '$ (selector) .first()' * does * devuelve un objeto jQuery. No debe volver a envolverlo con '$ ($ (selector) .first())'. El único método jQuery (que yo sepa) que devuelve un elemento DOM simple es '.get (0)' cuando le pasa un número. Sin el argumento número, obtienes una matriz de elementos DOM. – user113716

0

¿Vio usted .each vs jQuery.each

Usted debe ser capaz de hacer lo siguiente:

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

por el primer enlace. Trate $(this) en lugar de $(obj)

+0

Esto no es diferente en forma significativa. Todavía necesito hacer objetos jQuery. – badp

0

tratan

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

El constructor '$()' todavía está allí. – badp

0

Creo que, dado que jQuery usa objetos de envoltura, el primer método usa el envoltorio original, y simplemente elimina todos menos el primer elemento del envoltorio, manteniéndolo así como un objeto jQuery.

Sin embargo, si tuvieran que alimentar un objeto jQuery para cada uno de los nodos para la función each(), incurrirían en la sobrecarga de crear el contenedor para cada uno. Y dado que no necesariamente quiere ese objeto envoltorio, incurriría en una sobrecarga innecesaria.

1

Internamente jQuery llamar a esto para $("sel").each(function(){});

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

Y el eq es una rebanada simple:

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

Así se puede crear una nueva función each que en lugar de object[name] hará un object:eq(i)

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

Así que para crear su propio 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 
}); 

Parece que each3 es más rápido que 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

Entonces, ¿podría funcionar [esto] (http://gist.github.com/629941)? :) También ahora necesito hacer algunos perfiles para entender lo que sea más rápido. – badp

+0

@badp: Sí. No creo que haya mucha diferencia en 'obj [i]' y 'obj.slice (i, i + 1)' ... Ver el ejemplo aquí http://www.jsfiddle.net/m7pKk/ – BrunoLM

+0

@ BrunoLM, en realidad '$ (". Foo ") [i]' devuelve un objeto DOM mientras que '$ (". Foo "). Eq (i)' da un objeto jQuery. El punto más importante aquí, y dada la implementación de 'eq' a través de las divisiones, casi me hacen creer que' $ ($ (". Foo") [i]) 'sería más rápido ... – badp

1

Ahí está el impacto en el rendimiento obvio que sería tomado por iteración. Al crear un nuevo objeto jQuery cada iteración sería mucho más lenta y probablemente notable en colecciones grandes. Muy a menudo, no necesita la conveniencia adicional del objeto envuelto, especialmente al acceder a propiedades o atributos individuales. Con demasiada frecuencia, ve el código de pérdida de ciclo como $(this).is(":checked") en lugar de this.checked.

Aparte de eso, sin embargo, diría que es porque tiene sentido. Un objeto jQuery típicamente representa una colección de objetos DOM que pueden tener cualquier número de tamaño. A veces, jQuery se usa exclusivamente para su soporte de selector y enlace de eventos, y no mucho más allá de eso. No tiene mucho sentido devolver una colección que contenga un elemento único al iterar sobre una colección de más elementos. Tiene mucho más sentido devolver un elemento individual que es más probable que necesite, el elemento DOM, luego puede envolverlo con jQuery si desea las características adicionales. Esto también lo mantiene en línea con iterar sobre NodeList y otros tipos de colección.

0

Probablemente porque, en su ejemplo, no hay ninguna razón para usar incluso each. En lugar de:

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

sólo tiene que utilizar:

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

Todo es automáticamente plural cuando se trata de conjuntos de jQuery.

+1

Necesitaré llamar a una función por golpe que es más complicada que una llamada '.text()' :) – badp

+0

Pero eso es lo correcto - si necesita hacer algo único para cada elemento en el conjunto , ¿tiene sentido incluso seleccionarlos todos juntos con ".foo"? – jpsimons

+0

sí, si quiero, por ejemplo, aplicar una función matemática al valor en cada ".foo". La misma función, entrada diferente, salida diferente. – badp

Cuestiones relacionadas