1. Code
  2. JavaScript
  3. jQuery

14 Útiles Trucos, Notas y Buenas Prácticas para jQuery

Si hay algo malo acerca de jQuery, es que el nivel de entrada es tan sorprendentemente bajo, que tiende a atraer a aquellos que no tienen ni una onza de conocimiento de JavaScript. Ahora, por un lado, esto es fantástico. Sin embargo, por otro lado, también da como resultado una mezcla de, francamente, un código desagradablemente malo (¡algo de el escrito por mí mismo!).
Scroll to top

Spanish (Español) translation by Jorge Montoya (you can also view the original English article)

Si hay algo malo acerca de jQuery, es que el nivel de entrada es tan sorprendentemente bajo, que tiende a atraer a aquellos que no tienen ni una onza de conocimiento de JavaScript. Ahora, por un lado, esto es fantástico. Sin embargo, por otro lado, también da como resultado una mezcla de, francamente, un código desagradablemente malo (¡algo de el escrito por mí mismo!).

Pero eso está bien; un código aterradoramente pobre que incluso haría jadear a su abuela es un rito de iniciación. La clave es escalar la colina, y eso es lo que discutiremos en el tutorial de hoy.


1. Métodos Devuelven el Objeto jQuery

Es importante recordar que la mayoría de los métodos devolverán el objeto jQuery. Esto es extremadamente útil y permite la funcionalidad de encadenamiento que utilizamos con tanta frecuencia.

1
$someDiv
2
  .attr('class', 'someClass')
3
  .hide()
4
  .html('new stuff');

Sabiendo que el objeto jQuery siempre se devuelve, podemos utilizarlo para eliminar el código superfluo a veces. Por ejemplo, considere el siguiente código:

1
var someDiv = $('#someDiv');
2
someDiv.hide();

La razón por la que "almacenamos en caché" la ubicación del elemento someDiv es para limitar el número de veces que tenemos que atravesar el DOM para este elemento por una vez.

El código anterior está perfectamente bien; sin embargo, usted podría combinar fácilmente las dos líneas en una, mientras logras el mismo resultado.

1
var someDiv = $('#someDiv').hide();

De esta forma, aún ocultamos el elemento someDiv, pero el método además, como hemos aprendido, devuelve el objeto jQuery -- el cual luego se referencia a través de la variable someDiv.


2. El Selector Find

Siempre y cuando sus selectores no sean ridículamente pobres, jQuery hace un trabajo fantástico al optimizarlos de la mejor manera posible y en general, usted no necesita preocuparse demasiado por ellos. Sin embargo, dicho esto, hay un puñado de mejoras que puede hacer que mejorarán algo el rendimiento de su script.

Una de esas soluciones es utilizar el método find(), cuando sea posible. La clave está lejos de forzar a jQuery a usar su motor Sizzle, si no es necesario. Ciertamente, habrá momentos en que esto no sea posible -- y eso está bien; pero, si no requiere la sobrecarga adicional, no vaya a buscarla.

1
// Fine in modern browsers, though Sizzle does begin "running"

2
$('#someDiv p.someClass').hide();
3
4
// Better for all browsers, and Sizzle never inits.

5
$('#someDiv').find('p.someClass').hide();

Los últimos navegadores modernos tienen soporte para QuerySelectorAll, que le permite pasar selectores similares a CSS, sin la necesidad de jQuery. jQuery también comprueba esta función.

Sin embargo, los navegadores más antiguos, es decir IE6/IE7, comprensiblemente no brindan soporte. Lo que esto significa es que estos selectores más complicados activan el motor Sizzle completo de jQuery, que, aunque brillante, viene con un poco más de sobrecarga.

Sizzle es una cantidad brillante de código que nunca podré entender. Sin embargo, en una oración, primero toma su selector y lo convierte en un "array" compuesto por cada componente de su selector.

1
// Rough idea of how it works

2
 ['#someDiv, 'p'];

Luego, de derecha a izquierda, comienza a descifrar cada elemento con expresiones regulares. Lo que esto significa también es que la parte más a la derecha de su selector debe ser lo más específica posible -- por ejemplo, un nombre de id o de etiqueta.

En pocas palabras, cuando sea posible:

  • Mantenga sus selectores simples
  • Utilice el método find(). De esta manera, en lugar de usar Sizzle, podemos continuar usando las funciones nativas del navegador.
  • Al utilizar Sizzle, optimice la parte de la derecha de su selector tanto como sea posible.

¿Contexto en su Lugar?

También es posible agregar un contexto a sus selectores, como por ejemplo:

1
$('.someElements', '#someContainer').hide();

Este código ordena a jQuery que envuelva una colección de todos los elementos con una clase someElements -- que son hijos de someContainer -- dentro de jQuery. Utilizar un contexto es una forma útil de limitar el cruce DOM, sin embargo tras bambalinas, jQuery usa el método find en su lugar.

1
$('#someContainer')
2
  .find('.someElements')
3
  .hide();

Prueba

1
// HANDLE: $(expr, context)

2
// (which is just equivalent to: $(context).find(expr)

3
} else {
4
   return jQuery( context ).find( selector );
5
}

3. No Abuse de $(this)

Sin conocer las distintas propiedades y funciones DOM, puede ser fácil abusar innecesariamente del objeto jQuery. Por ejemplo:

1
$('#someAnchor').click(function() {
2
  // Bleh

3
	alert( $(this).attr('id') );
4
});

Si nuestra única necesidad del objeto jQuery es acceder al atributo de id de la etiqueta ancla, esto es un desperdicio. Mejor seguir con JavaScript "crudo".

1
$('#someAnchor').click(function() {
2
	alert( this.id );
3
});

Tenga en cuenta que hay tres atributos a los que siempre se debe acceder, a través de jQuery: "src", "href" y "style". Estos atributos requieren el uso de getAttribute en versiones antiguas de IE.

Prueba

1
// jQuery Source

2
var rspecialurl = /href|src|style/;
3
// ... 

4
var special = rspecialurl.test( name );
5
// ...

6
var attr = !jQuery.support.hrefNormalized && notxml && special ?
7
	// Some attributes require a special call on IE

8
	elem.getAttribute( name, 2 ) :
9
	elem.getAttribute( name );

Múltiples Objetos jQuery

Aún peor es el proceso de consultar repetidamente el DOM y crear múltiples objetos jQuery.

1
	$('#elem').hide();
2
	$('#elem').html('bla');
3
	$('#elem').otherStuff();

Con suerte, ya sabe lo ineficiente que es este código. Si no, está bien; todos estamos aprendiendo La respuesta es implementar encadenamiento o "almacenar en caché" la ubicación de #elem.

1
	// This works better

2
	$('#elem')
3
	  .hide()
4
	  .html('bla')
5
	  .otherStuff();
6
7
	// Or this, if you prefer for some reason.

8
	var elem = $('#elem');
9
	elem.hide();
10
	elem.html('bla');
11
	elem.otherStuff();

4. Método Abreviado Ready de jQuery

Escuchar cuando el documento está listo para ser manipulado es ridículamente simple con jQuery.

1
$(document).ready(function() {
2
	// let's get up in heeya

3
});

Sin embargo, es muy posible que se haya topado con una función de envoltura diferente y más confusa.

1
$(function() {
2
	// let's get up in heeya

3
});

Aunque este último es algo menos legible, los dos fragmentos son idénticos. ¿No me cree? Solo revise la fuente jQuery.

1
// HANDLE: $(function)

2
// Shortcut for document ready

3
if ( jQuery.isFunction( selector ) ) {
4
	return rootjQuery.ready( selector );
5
}

rootjQuery es simplemente una referencia a la raíz jQuery(document). Cuando pasa un selector a la función jQuery, este determinará qué tipo de selector pasó: cadena, etiqueta, identificación, función, etc. Si se pasó una función, jQuery llamará a su método ready() y pasará su función anónima como el selector.


5. Mantenga su Código Seguro

Si desarrolla código para distribución, siempre es importante compensar cualquier posible conflicto de nombres. ¿Qué pasaría si algún script, importado después del suyo, también tuviese una función $? ¡Cosas malas!

La respuesta es invocar a noConflict() de jQuery, o almacenar su código dentro de una función anónima de invocación automática, y luego pasarle jQuery.

Método 1: NoConflict

1
var j = jQuery.noConflict();
2
// Now, instead of $, we use j. 

3
j('#someDiv').hide();
4
5
// The line below will reference some other library's $ function.

6
$('someDiv').style.display = 'none';

Tenga cuidado con este método y trate de no usarlo cuando distribuya su código. ¡Realmente confundiría al usuario de su script! :)

Método 2: Pasar jQuery

1
(function($) {
2
	// Within this function, $ will always refer to jQuery

3
})(jQuery);

Los paréntesis finales en la parte inferior llaman a la función automáticamente - function(){}(). Sin embargo, cuando llamamos a la función, también pasamos jQuery, que está representado por $.

Método 3: Pasar $ a Través del Método Ready

1
jQuery(document).ready(function($) {
2
 // $ refers to jQuery

3
});
4
5
// $ is either undefined, or refers to some other library's function.

6. Sea Inteligente

Recuerde: jQuery es solo JavaScript. No suponga que tiene la capacidad de compensar su mala codificación. :)

Esto significa que, así como debemos optimizar cosas como declaciones for de JavaScript, lo mismo es cierto para el método each de jQuery. ¿Y por qué no deberíamos? Es solo un método de ayuda, que luego crea una declaración for  detrás de escenas.

1
// jQuery's each method source

2
	each: function( object, callback, args ) {
3
		var name, i = 0,
4
			length = object.length,
5
			isObj = length === undefined || jQuery.isFunction(object);
6
7
		if ( args ) {
8
			if ( isObj ) {
9
				for ( name in object ) {
10
					if ( callback.apply( object[ name ], args ) === false ) {
11
						break;
12
					}
13
				}
14
			} else {
15
				for ( ; i < length; ) {
16
					if ( callback.apply( object[ i++ ], args ) === false ) {
17
						break;
18
					}
19
				}
20
			}
21
22
		// A special, fast, case for the most common use of each

23
		} else {
24
			if ( isObj ) {
25
				for ( name in object ) {
26
					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
27
						break;
28
					}
29
				}
30
			} else {
31
				for ( var value = object[0];
32
					i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
33
			}
34
		}
35
36
		return object;
37
	}

Horrible

1
someDivs.each(function() {
2
	$('#anotherDiv')[0].innerHTML += $(this).text();
3
});
  1. Busca anotherDiv por cada iteración
  2. Toma la propiedad innerHTML dos veces
  3. Crea un nuevo objeto jQuery, todo para acceder al texto del elemento.

Mejor

1
var someDivs = $('#container').find('.someDivs'),
2
      contents = [];
3
4
someDivs.each(function() {
5
	contents.push( this.innerHTML );
6
});
7
$('#anotherDiv').html( contents.join('') );

De esta forma, dentro del método each (for), la única tarea que estamos realizando es agregar una nueva clave a un array ... en lugar de consultar el DOM, tomar dos veces la propiedad innerHTML del elemento, etc.

Este consejo está más basado en JavaScript en general, en lugar de específico en jQuery. El punto es recordar que jQuery no compensa la pobre codificación.

Fragmentos de Documentos

Mientras estamos en eso, otra opción para este tipo de situaciones es usar fragmentos de documentos.

1
var someUls = $('#container').find('.someUls'),
2
	frag = document.createDocumentFragment(),
3
	li;
4
	
5
someUls.each(function() {
6
	li = document.createElement('li');
7
	li.appendChild( document.createTextNode(this.innerHTML) );
8
	frag.appendChild(li);
9
});
10
11
$('#anotherUl')[0].appendChild( frag );

La clave aquí es que hay múltiples formas de llevar a cabo tareas simples como esta, y cada una tiene sus propios beneficios de rendimiento de navegador a navegador. Cuanto más se quede con jQuery y aprenda JavaScript, también puede encontrar que se refiera a las propiedades y métodos nativos de JavaScript con más frecuencia. Y, si es así, ¡eso es fantástico!

jQuery proporciona un sorprendente nivel de abstracción que debe aprovechar, pero esto no significa que esté obligado a utilizar sus métodos. Por ejemplo, en el ejemplo de fragmento anterior, usamos el método each de jQuery. Si prefiere usar un enunciado for o while en vez de eso, ¡está bien también!

Con todo eso dicho, tenga en cuenta que el equipo de jQuery ha optimizado mucho esta biblioteca. Los debates sobre each() de jQuery frente a la declaración nativa for son tontos y triviales. Si está utilizando jQuery en su proyecto, ahorre tiempo y use sus métodos de ayuda. ¡Para eso están allí! :)


7. Métodos AJAX

Si recién está empezando a profundizar en jQuery, los diversos métodos AJAX que ponemos a nuestra disposición pueden resultar un tanto desalentadores; aunque no deberían serlo. De hecho, la mayoría de ellos son simplemente métodos auxiliares, que se dirigen directamente a $.ajax.

  • get
  • getJSON
  • post
  • ajax

Como ejemplo, revisemos getJSON, que nos permite buscar JSON.

1
$.getJSON('path/to/json', function(results) {
2
	// callback

3
	// results contains the returned data object

4
});

Detrás de escenas, este método primero llama $.get.

1
getJSON: function( url, data, callback ) {
2
	return jQuery.get(url, data, callback, "json");
3
}

$.get luego compila los datos pasados y de nuevo, llama al método "maestro" (de ordenamientos) $.ajax.

1
get: function( url, data, callback, type ) {
2
	// shift arguments if data argument was omited

3
	if ( jQuery.isFunction( data ) ) {
4
		type = type || callback;
5
		callback = data;
6
		data = null;
7
	}
8
9
	return jQuery.ajax({
10
		type: "GET",
11
		url: url,
12
		data: data,
13
		success: callback,
14
		dataType: type
15
	});
16
}

¡Finalmente, $.ajax realiza una gran cantidad de trabajo para permitirnos la capacidad de realizar solicitudes asíncronas con éxito en todos los navegadores!

Lo que esto significa es que puede usar el método $.ajax directamente y exclusivamente para todas sus solicitudes AJAX. Los otros métodos son simplemente métodos auxiliares que terminan haciendo esto de todos modos. Entonces, si quiere, corte al intermediario. No es un problema significativo de todas formas.

De Maravilla

1
$.getJSON('path/to/json', function(results) {
2
	// callback

3
	// results contains the returned data object

4
});

Microscópicamente Más Eficiente

1
$.ajax({
2
	type: 'GET',
3
	url : 'path/to/json',
4
	data : yourData,
5
	dataType : 'json',
6
	success : function( results ) {
7
		console.log('success');
8
	})
9
});

8. Accediendo a las Propiedades y Métodos Nativos

Así que aprendió un poco de JavaScript y aprendió que, por ejemplo, en las etiquetas ancla, puede acceder directamente a los valores de los atributos:

1
var anchor = document.getElementById('someAnchor');
2
 //anchor.id

3
// anchor.href

4
// anchor.title

5
// .etc

El único problema es que esto no parece funcionar cuando usted referencia a los elementos DOM con jQuery, ¿verdad? Bueno, por supuesto que no.

No Funcionará

1
	// Fails

2
	var id = $('#someAnchor').id;

Entonces, si necesita acceder al atributo href (o cualquier otra propiedad o método nativo para ese caso), tiene un puñado de opciones.

1
// OPTION 1 - Use jQuery

2
var id = $('#someAnchor').attr('id');
3
4
// OPTION 2 - Access the DOM element

5
var id = $('#someAnchor')[0].id;
6
7
// OPTION 3 - Use jQuery's get method

8
var id = $('#someAnchor').get(0).id;
9
10
// OPTION 3b - Don't pass an index to get

11
anchorsArray = $('.someAnchors').get();
12
var thirdId = anchorsArray[2].id;

El método get es particularmente útil, ya que transforma su colección jQuery en un array.


9. Detecte las Solicitudes de AJAX con PHP

Ciertamente, para la gran mayoría de nuestros proyectos, no solo podemos confiar en JavaScript para cosas como validación o solicitudes AJAX. ¿Qué sucede cuando JavaScript está desactivado? Por esta misma razón, una técnica común es detectar si se ha realizado una solicitud AJAX con el lenguaje de servidor de su elección.

jQuery lo hace ridículamente simple, estableciendo un encabezado dentro del método $.ajax.

1
// Set header so the called script knows that it's an XMLHttpRequest

2
// Only send the header if it's not a remote XHR

3
if ( !remote ) {
4
	xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
5
}

Con este conjunto de encabezado, ahora podemos usar PHP (o cualquier otro lenguaje) para verificar este encabezado y proceder en consecuencia. Para esto, verificamos el valor de $_SERVER ['HTTP_X_REQUESTED_WITH'].

Envoltura

1
function isXhr() {
2
  return $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
3
}

10. jQuery y $

¿Alguna vez se preguntó por qué/cómo puede usar jQuery y $ indistintamente? Para encontrar su respuesta, vea la fuente jQuery y desplácese hasta el final. Ahí, verá:

1
window.jQuery = window.$ = jQuery;

Todo el script de jQuery está, por supuesto, dentro de una función autoejecutable, que permite que el script limite el número de variables globales tanto como sea posible. Lo que también significa, sin embargo, es que el objeto jQuery no está disponible fuera de la función anónima de envoltura.

Para solucionar esto, jQuery está expuesto al objeto global window y en el proceso, también se crea un alias - $ -.


11. Cargar jQuery Condicionalmente

HTML5 Boilerplate ofrece un ingenioso código de una línea que cargará una copia local de jQuery si, por alguna extraña razón, su CDN elegido no funciona.

1
<!-- Grab Google CDN jQuery. fall back to local if necessary -->
2
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

3
<script>!window.jQuery && document.write('<script src="js/jquery-1.4.2.min.js"><\/script>')</script>

Para "frasear" el código anterior: si window.jQuery no está definido, debe haber un problema al descargar el script del CDN. En ese caso, proceda al lado derecho del operador && e inserte un script que enlace a una versión local de jQuery.


12. Filtros jQuery

1
<script>
2
	$('p:first').data('info', 'value'); // populates $'s data object to have something to work with
3
	
4
	$.extend(
5
		jQuery.expr[":"], {
6
			block: function(elem) {
7
				return $(elem).css("display") === "block";
8
			},
9
			
10
			hasData : function(elem) {				
11
				return !$.isEmptyObject( $(elem).data() );
12
			}
13
		}
14
	);
15
	
16
	$("p:hasData").text("has data"); // grabs paras that have data attached
17
	$("p:block").text("are block level"); // grabs only paragraphs that have a display of "block"
18
</script>

Nota: jQuery.expr [':'] es simplemente un alias para jQuery.expr.filters.


13. Una Sola Función de Hover

A partir de jQuery 1.4, ahora podemos pasar solo una función al método hover. Antes, se requerían los métodos de entrada y salida.

Antes

1
$('#someElement').hover(function() {
2
  // mouseover

3
}, function() {
4
 // mouseout

5
});

Ahora

1
$('#someElement').hover(function() {
2
  // the toggle() method can be used here, if applicable

3
});

Tenga en cuenta que esto no es una comparación viejo vs. nuevo. Muchas veces, todavía necesitará pasar dos funciones a hover, y eso es perfectamente aceptable. Sin embargo, si solo necesita alternar algún elemento (o algo así), pasar una sola función anónima ¡ahorrará un puñado de caracteres o algo así!


14. Pasando un Objeto de Atributo

A partir de jQuery 1.4, ahora podemos pasar un objeto como el segundo parámetro de la función jQuery. Esto es útil cuando necesitamos insertar nuevos elementos en el DOM. Por ejemplo:

Antes

1
$('<a />')
2
  .attr({
3
    id : 'someId',
4
    className : 'someClass',
5
    href : 'somePath.html'
6
  });

Después

1
$('</a>', {
2
    id : 'someId',
3
    className : 'someClass',
4
    href : 'somePath.html'
5
});

Esto no solo ahorra algunos caracteres, sino que también genera un código más limpio. Además de los atributos de los elementos, incluso podemos pasar atributos y eventos específicos de jQuery, como click o text.


¡Gracias por leer!