2010-01-16 30 views
29

Siempre me pregunté por qué jQuery devuelve verdadero si estoy tratando de encontrar elementos por selector de id. Que no existen en la estructura DOM.

De esta manera:

<div id="one">one</div> 

<script> 
    console.log(!!$('#one')) // prints true 
    console.log(!!$('#two')) // is also true! (empty jQuery object) 
    console.log(!!document.getElementById('two')) // prints false 
</script> 

Sé que puedo utilizar !!$('#two').length puesto que la longitud === 0 si el objeto está vacío, pero me parece lógico que un selector devolvería el elemento si se encuentra, de lo contrario null (como el nativo document.getElementById hace).

F.ex, esta lógica no se puede hacer en jQuery:

var div = $('#two') || $('<div id="two"></div>'); 

¿No sería más lógico que el selector de ID devuelto nulo si no lo encuentra?

anyone?

Respuesta

46

Este comportamiento fue elegido porque de lo contrario jQuery tiraría regularmente excepciones NullReference

Casi todas las funciones de jQuery devuelven un objeto jQuery como una envoltura alrededor de los elementos del DOM en cuestión, por lo que puede utilizar notación de puntos

$("#balloon").css({"color":"red"}); 

Ahora imaginemos $("#balloon") regresaron nula. Eso significa que $("#balloon").css({"color":"red"}); arrojaría un error, en lugar de hacer nada silenciosamente como era de esperar.

Por lo tanto, solo tienes que usar .length o .size().

+3

También pensaba que esta era una de las razones. Pero, ¿es realmente una buena idea suprimir los errores de esta manera? Si no se encuentra el ID, me gustaría saber dónde se produce el error en lugar de depurar cada cadena. – David

+1

Este podría ser el comportamiento que desea si usa el selector de id, ya que los identificadores son (normalmente) únicos. Pero, ¿qué sucede si utiliza un selector de clase para cerrar todos los cuadros de diálogo/ventanas emergentes en una página? No desearía que la función arrojara un error solo porque el usuario no tenía actualmente ningún diálogo abierto. Quisieras que silenciosamente no hiciera nada. – Dan

+2

JavaScript no tiene nada llamado Excepciones de NullReference. ¿Quizás te refieres a 'ReferenceError'? –

8

Así es como funciona jQuery.

$("#something")

objeto 0 = div # algo longitud = 1 = jQuery 1.2.6

$("#nothing")

objeto de longitud = 0 = jQuery 1.2.6

5

Puede acercarse hacer lo que quiera accediendo a la longitud del elemento, y combinarlo con el operador ternario:

console.log(!!$('#notfound').length); // false 
console.log(!!$('#exists').length); // true 
var element= $('#notfound').length ? $('#notfound') : $('#exists'); 
console.log(element.attr('id')); // outputs 'exists' 

En cuanto al fondo de la cuestión:

¿No sería más lógico si el selector de ID volvió nula si no lo encuentra?

No, no es por la forma de hacer las cosas jQuery - es decir, para apoyar el encadenamiento de las declaraciones de JQuery:

$('#notfound').hide("slow", function(){ 
     jQuery(this) 
     .addClass("done") 
     .find("span") 
      .addClass("done") 
     .end() 
     .show("slow", function(){ 
      jQuery(this).removeClass("done"); 
     }); 
    }); 

A pesar de que no existe notfound este código se ejecutará sin detener la ejecución del script. Si el selector inicial devuelve nulo, deberá agregar un bloque if/then para verificar el nulo. Si los métodos addClass, find, end y show devuelven null, tendrá que agregar un bloque if/then para verificar el estado de devolución de cada uno. El encadenamiento es una excelente manera de manejar el flujo de programa en un lenguaje de tipado dinámico como Javascript.

2

Puede verificar la propiedad .length del objeto jQuery. De esta manera:

if($("#two").length > 0) { // exists... 

} else { // doesn't exist 

} 
+1

Eso es una agradable. En realidad, todavía se puede acortar: 'if ($ (" # two "). Length)' también debería ser el truco. – miek

0

En resumen, podría pensar en el valor de retorno del selector jQuery como un grupo que contiene elementos 0..n, pero nunca es nulo.

Lo que probablemente le interese realmente es $("#two")[0], que le dará el primer elemento real devuelto por el selector.

+0

'$ (" # two: first ")' aún devolverá un objeto jQuery. – James

+0

Gracias J-P, estoy corregido. Actualizado la respuesta. – miek

3

Devuelve true porque para Javascript es un objeto definido, por lo tanto, no es falso, y jQuery siempre le dará un nuevo objeto independientemente de si el elemento se encuentra o no; sin embargo, la longitud del conjunto será cero, p.

$("span").length

Si no tiene <span>, esto va a ser cero, pero podría ser de 1 o más.

Puede escribir su propio complemento para evitar declaraciones if repetidas como un plugin de Jquery, como lo hice para this one. Es bastante fácil de hacer:

(function($) 
{ 
     /* Checks if a jQuery object exists in the DOM, by checking the length of its child elements. */ 
     $.fn.elementExists = function() 
     { 
       ///  <summary> 
       ///  Checks if a jQuery object exists in the DOM, by checking the length of its child elements. 
       ///  </summary> 
       ///  <returns type="Boolean" /> 
       return jQuery(this).length > 0; 
     }; 
})(jQuery); 

Uso:

if ($("#someid").elementExists()) 
{ 

} 
Cuestiones relacionadas