14 útiles trucos, notas y mejores prácticas de jQuery

Balu1 Octubre 2010 - 5:26pm 10 comentarios
Enviar por Email Imprimir

14 útiles trucos, notas y mejores prácticas de jQuery

Si hay algo bueno con jQuery es que no sólo trata de facilitar el trabajo de los desarrolladores de JavaScript; sino también, introducir a aquellos que no tienen muchos conocimientos sobre JS, a crear sus propios efectos, programar cosas sencillas, etc. muy rápidamente.

Sin embargo, la clave para no terminar escribiendo un código de poca calidad, es tener presente algunas ideas y tips básicos a la hora de desarrollar nuestro código. En este artículo veremos 14 trucos, notas y mejores prácticas para programar con jQuery, que todos debemos conocer...

1. Maneras de retornar el objeto jQuery

Es importante recordar que la mayoría de métodos retornarán el objeto jQuery. Esto es muy útil, ya que nos permite usar el encadenamiento de métodos, muy a menudo.

$someDiv
  .attr('class', 'someClass')
  .hide()
  .html('new stuff');

Sabiendo que siempre se devuelve el objeto jQuery, podemos usarlo para eliminar código sobrante. Por ejemplo, veamos el siguiente código:

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

La razón por la que "cacheamos" la ubicación del elemento someDiv es la de limitar a una, el número de veces que tenemos que recorrer el DOM para encontrar el elemento.

El código anterior es correcto; sin embargo, podríamos combinar ambas líneas y obtener el mismo resultado:

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

De esta manera, aunque ocultamos el elemento someDiv, el método también devolverá el objeto jQuery; por lo que, luego podemos hacer referencia al elemento, a través de la variable someDiv.

2. El selector Find

jQuery nos ofrece una variedad de selectores y hace un buen trabajo al optimizarlos; tanto, que por lo general, no hay necesidad de preocuparse por ellos. Sin embargo, hay un puñado de cosas que podemos hacer para mejorar el rendimiento de nuestros scripts.

Una de ellas es utilizar el método find(), tanto como sea posible. La clave esta en no forzar a que jQuery a utilizar su motor  Sizzle, si no es necesario. Desde luego, habrá momentos en que esto no sea posible y está bien; pero, si no se requiere de la sobrecarga adicional, no hay porque buscarla.

// Bien en navegadores modernos, aunque Sizzle se inicia "en marcha" 
$('#someDiv p.someClass').hide();

// Mejor para todos los navegadores y Sizzle nunca inicia
$('#someDiv').find('p.someClass').hide();

Las últimas versiones de los navegadores modernos (con WebKit ó +Firefox 3.1) implementan el método QuerySelectorAll(), que nos permite usar selectores, al igual como lo hacemos con CSS, sin la necesidad de usar jQuery... jQuery también comprueba esta funcionalidad.

Sin embargo, los navegadores más antiguos, como IE6/IE7, no tienen esta característica; por lo que estos selectores hacen uso del motor Sizzle; que, aunque es muy bueno, ocasionan un poco más de sobrecarga.

Sizzle es un genial trozo de código que no es tan fácil de entender; pero que si lo explicamos, en una oración, diríamos que: Coge tu selector y lo convierte en un "array" conformado por cada componente de tu selector.

// Tosca idea de cómo funciona 
 ['#someDiv, 'p'];

Luego, de derecha a izquierda, empezará a descifrar cada elemento con expresiones regulares. Esto quiere decir, que la parte más a la derecha de tu selector deberá ser la más específica posible, por ejemplo, un id o un nombre de etiqueta.

En pocas palabras, cuando sea posible debemos:

  • Mantener simples nuestros selectores
  • Utilizar el método find(). De esta manera, en lugar de usar Sizzle, podemos continuar usando las funciones nativas de los navegadores.
  • Cuando usamos Sizzle, debemos optimizar la parte que esta más a la derecha de nuestro selector, tanto como sea posible.

¿El lugar del contexto?

También es posible añadir un contexto a los selectores, por ejemplo:

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

Este código le dice a jQuery que englobe a todos los elementos que tengan la clase someElements y que sean hijos de someContainer. De esta manera, usar un contexto es una manera útil de limitar el recorrido del DOM; sin embargo, behind the scenes, jQuery esta utilizando el método find().

$('#someContainer')
  .find('.someElements')
  .hide();

Prueba

// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
   return jQuery( context ).find( selector );
}

3. No abuses de $(this)

Si no somos muy conocedores de las propiedades y funciones del DOM, puede que terminemos abusando del objeto jQuery innecesariamente. Por ejemplo:

$('#someAnchor').click(function() {
	// Bleh
	alert( $(this).attr('id') );
});

Si sólo necesitamos usar el objeto jQuery para acceder al atributo de un elemento, usar jQuery sería un desperdicio. Mejor nos quedamos con el JavaScript "plano".

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

Noten que que hay tres atributos que siempre deben ser accedidos vía jQuery: "src", "href" y "style". Estos atributos requieren el uso de getAttribute en las versiones antiguas de IE.

Prueba

// Código fuente de jQuery
var rspecialurl = /href|src|style/;
// ...
var special = rspecialurl.test( name );
// ...
var attr = !jQuery.support.hrefNormalized && notxml && special ?
	// Some attributes require a special call on IE
	elem.getAttribute( name, 2 ) :
	elem.getAttribute( name );

Múltiples Objetos jQuery

Peor aún es el proceso de consultar el DOM repetitivamente y crear varios objetos de jQuery.

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

Afortunadamente, ya estamos enterados de lo ineficiente que es este código. Si no, esta bien, estamos aprendiendo. La solución es poner en práctica el encadenamiento o "cachear" la ubicación de #elem.

	// Esto funciona mejor
	$('#elem')
	  .hide()
	  .html('bla')
	  .otherStuff();

	// O esto, si lo prefieres por alguna razón
	var elem = $('#elem');
	elem.hide();
	elem.html('bla');
	elem.otherStuff();

4. El método Ready más ligero

Esperar a que el documento este listo para ser usado, es muy fácil con jQuery.

$(document).ready(function() {
	// vamos a llegar en heeya 
});

Sin embargo, es muy posible que nos hayamos encontrado con diferentes funciones, volviendo esto algo confuso.

$(function() {
	// vamos a llegar en heeya 
});

Aunque este último código es un poco menos legible, los dos fragmentos son idénticos. ¿No me crees? Sólo tienes que chequear el código fuente de jQuery.

// HANDLE: $(function)
// Acceso rápido para ready
if ( jQuery.isFunction( selector ) ) {
	return rootjQuery.ready( selector );
}

rootjQuery es simplemente una referencia a la raíz de jQuery(document). Cuando pasamos un selector a la función de jQuery, esta determinará que tipo de selector hemos pasado: string, tag, id, función, etc. Si una función fue pasada, jQuery llamará al método ready() y pasará la función anónima como el selector.

5. Mantén tu código seguro

Si desarrollas código para distribuirlo, es importante considerar algún posible conflicto de nombres. ¿Qué pasaría si un script es importando antes que el tuyo y también hace uso de una función $? Hmm...

La solución es llamar al método noConflict() de jQuery, o almacenar el código dentro de una función anónima que se auto invoque y luego pasarla a jQuery.

Método 1: NoConflict

var j = jQuery.noConflict();
// Ahora, en vez de $, usamos j.
j('#someDiv').hide();

// La siguiente linea referenciará a otra librería con la función $
$('someDiv').style.display = 'none';

Hay que tener cuidado con este método y tratar de no usarlo cuando distribuimos nuestro código. ¡Realmente podríamos confundir al usuario de nuestro script! :-)

Método 2: Pasar a jQuery

(function($) {
	// En esta función, $ siempre se referirá a jQuery
})(jQuery);

El paréntesis, al final de todo el script, llamará a la función automáticamente – function(){}(). Sin embargo, cuando llamamos a la función, también pasamos jQuery, el cual es representado por el $.

Método 3: Pasar $ vía el método Ready

jQuery(document).ready(function($) {
 // $ se refiere a jQuery
});

// $ esta indefinido o se refiere a la función de otra librería

6. Se inteligente

Recuerden: jQuery es sólo JavaScript. No crean que tiene la capacidad de compensar una mala programación.

Esto significa que, al igual que debemos optimizar cosas como el bucle for de JavaScript; lo mismo debemos hacer con el método each de jQuery. ¿Y por qué debemos hacerlo? Porque each es sólo un método de ayuda, que por dentro crea un for.

// código fuente del método each de jQuery
	each: function( object, callback, args ) {
		var name, i = 0,
			length = object.length,
			isObj = length === undefined || jQuery.isFunction(object);

		if ( args ) {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.apply( object[ name ], args ) === false ) {
						break;
					}
				}
			} else {
				for ( ; i < length; ) {
					if ( callback.apply( object[ i++ ], args ) === false ) {
						break;
					}
				}
			}

		// Un especial y rápido caso para el uso común de each
		} else {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
						break;
					}
				}
			} else {
				for ( var value = object[0];
					i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
			}
		}

		return object;
	}

Horrible

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

Mejor

var someDivs = $('#container').find('.someDivs'),
      contents = [];

someDivs.each(function() {
	contents.push( this.innerHTML );
});
$('#anotherDiv').html( contents.join('') );

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

Este tip esta más basado en JavaScript; pero de manera específica también se aplica en jQuery. El punto a recordar es que usar jQuery no compensa una programación pobre.

Fragmentos del documento

Mientras tanto, otra alternativa para este tipo de situaciones es usar fragmentos del documento.

var someUls = $('#container').find('.someUls'),
	frag = document.createDocumentFragment(),
	li;

someUls.each(function() {
	li = document.createElement('li');
	li.appendChild( document.createTextNode(this.innerHTML) );
	frag.appendChild(li);
});

$('#anotherUl')[0].appendChild( frag );

La clave aquí es saber que hay varias maneras de realizar tareas sencillas como esta. Y cada una de ellas, tiene mejoras de rendimiento, dependiendo del navegador que se use. Cuanto más usemos jQuery y aprendamos JavaScript, podremos encontrar más referencias a las propiedades y métodos nativos de JavaScript. ¡Y esto es fantástico!

Si bien, jQuery nos ofrece un impresionante nivel de abstracción que debemos aprovechar; esto no quiere decir que siempre estemos obligados a usar sus métodos. Por ejemplo, en el fragmento de código anterior, usamos el método each de jQuery. Pero, si utilizamos los bucles for o while en su lugar, también estaría muy bien.

Con todo lo dicho, hay que tener en cuenta que el equipo de jQuery ha optimizado bastante su framework. Los debates sobre each() frente a for resultan triviales. Si estamos usando jQuery en nuestro proyecto, debemos ahorrar tiempo y utilizar sus métodos de ayuda. ¡Que para eso fueron creados!

7. Métodos AJAX

Si recién estas introduciéndote en jQuery, los distintos métodos de Ajax que están a nuestra disposición podrían parecer un poco complicados (aunque no lo sean). De hecho, la mayoría de ellos son simplemente métodos de ayuda, que nos llevan directamente al método $.ajax.

  • get
  • getJSON
  • post
  • ajax

Como ejemplo, déjenme observar getJSON, el cual nos permite usar JSON.

$.getJSON('path/to/json', function(results) {
	// callback
	// results contiene los datos del objeto devuelto
});

Por dentro, este método primero llama a $.get.

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

$.get luego compila la data transmitida, y, nuevamente, llama al método "maestro" $.ajax.

get: function( url, data, callback, type ) {
	// modifica argumentos si el argumento de data fue omitido
	if ( jQuery.isFunction( data ) ) {
		type = type || callback;
		callback = data;
		data = null;
	}

	return jQuery.ajax({
		type: "GET",
		url: url,
		data: data,
		success: callback,
		dataType: type
	});
}

Finalmente, $.ajax lleva a cabo una enorme cantidad de trabajo que nos permite realizar peticiones asíncronas con éxito en todos los navegadores.

Lo que esto significa es que bien podríamos utilizar el método $.ajax directamente y exclusivamente para todas nuestras peticiones AJAX. Los otros métodos son simplemente métodos auxiliares que terminan haciendo lo mismo. Así que, si queremos, podríamos ahorrar camino; pero, no es un gran problema de todos modos.

Sólo por elegancia

$.getJSON('path/to/json', function(results) {
	// callback
	// results contiene los datos del objeto devuelto
});

Microscópicamente más eficiente

$.ajax({
	type: 'GET',
	url : 'path/to/json',
	data : yourData,
	dataType : 'json',
	success : function( results ) {
		console.log('success');
	})
});

8. Accediendo a propiedades y métodos nativos

Entonces, hemos aprendido un poco más sobre JavaScript y hemos visto que podemos acceder a los valores de los atributos directamente:

var anchor = document.getElementById('someAnchor');
  //anchor.id
  // anchor.href
  // anchor.title
  // .etc

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

No funciona

	// Falla
	var id = $('#someAnchor').id;

Por ello, si necesitamos acceder al atributo href (o cualquier otra propiedad o método nativo, dado el caso), tenemos un puñado de opciones.

// OPTION 1 - Usa jQuery
var id = $('#someAnchor').attr('id');

// OPTION 2 - Acceder a los elementos del DOM 
var id = $('#someAnchor')[0].id;

// OPTION 3 - Usa el método get de jQuery
var id = $('#someAnchor').get(0).id;

// OPTION 3b - No pasa un índice a get
anchorsArray = $('.someAnchors').get();
var thirdId = anchorsArray[2].id;

El getmethod es particularmente útil, ya que puede traducir nuestra colección de jQuery en un array.

9. Detectar peticiones AJAX con PHP

Ciertamente, gran parte de nuestros proyectos no sólo dependen de JavaScript para cosas como la validación o peticiones AJAX. ¿Qué sucede cuando JavaScript está desactivado? Por esta razón, una técnica común es detectar si una petición se ha hecho, con nuestro lenguaje de servidor favorito.

jQuery lo hace muy fácil, definiendo una cabecera dentro del método $.ajax.

// Define una cabecera para que el script llamado sepa que es un XMLHttpRequest
// Sólo envía la cabecerá si no es un XHR remoto
if ( !remote ) {
	xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}

Con esta cabecera definida, ahora podemos usar PHP (o cualquier otro lenguaje) para comprobar la existencia de la cabecera y proceder en consecuencia. Para ello, comprobamos el valor de $_SERVER ['HTTP_X_REQUESTED_WITH'].

Wrapper

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

10. jQuery y $

Alguna vez te preguntaste ¿Por qué/Cómo se puede usar jQuery y $ indistintamente? Para encontrar la respuesta, nos vamos al código fuente de jQuery y hacemos scroll hasta abajo. Allí veremos:

window.jQuery = window.$ = jQuery;

Todo el script de jQuery es, por supuesto, envuelto dentro de una función que se ejecuta automáticamente y que permite al script limitar el número de variables globales tanto cuanto sea posible. Lo que esto quiere decir, entonces, es que el objeto jQuery no esta disponible fuera de la función anónima que lo engloba.

Para solucionar este inconveniente, jQuery es expuesto al objeto window (global) y, en el proceso, el alias – $ – también es creado.

11. Cargando jQuery condicionalmente

HTML5 Boilerplate ofrece una ingeniosa línea de código que nos permite cargar una copia local de jQuery si, por alguna extraña razón, el CDN que usamos esta caído.


<!-- Utiliza jQuery del CDN de Google. Utiliza el jQuery local si es necesario -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>!window.jQuery && document.write('<script src="js/jquery-1.4.2.min.js"><\/script>')</script>

Si window.jQuery no esta definido, debe de haber un problema con la descarga del script del CDN. En este caso, continuamos con el lado derecho del operador && e insertamos el enlace al script local de jQuery.

12. Filtros de jQuery

	$('p:first').data('info', 'value'); // Añadimos un dato para tener algo con que trabajar

	$.extend(
		jQuery.expr[":"], {
			block: function(elem) {
				return $(elem).css("display") === "block";
			},

			hasData : function(elem) {
				return !$.isEmptyObject( $(elem).data() );
			}
		}
	);

	$("p:hasData").text("has data"); // filtra párrafos que tienen datos adjuntos 
	$("p:block").text("are block level"); // filtra párrafos que tienen como valor de display: "block" 

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

13. Una sola función para Hover

Desde jQuery 1.4, podemos pasar una sola función al método hover. Antes, debíamos pasar dos funciones, una para cuando el mouse pasa por encima de los elementos (in) y otra para cuando el mouse se sale de elemento (out).

Antes

$('#someElement').hover(function() {
  // mouseover
}, function() {
 // mouseout
});

Ahora

$('#someElement').hover(function() {
  // El método toggle() puede ser usado aquí, si es conveniente
});

Hay que tener en cuenta que esto no es un trato antiguo y uno nuevo. Muchas veces, podríamos tener que pasar ambas funciones a hover, lo que es perfectamente válido. Sin embargo, si sólo necesitamos cambiar un elemento (toggle, por ejemplo), pasando una sola función a Hover será más que suficiente y acortaremos el código un poco más.

14. Pasar un Objeto Atributo

También, desde jQuery 1.4, 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

$('')
  .attr({
    id : 'someId',
    className : 'someClass',
    href : 'somePath.html'
  });

Ahora

$('', {
    id : 'someId',
    className : 'someClass',
    href : 'somePath.html'
});

Esto no sólo nos permite escribir menos código, sino que vuelve nuestro código más limpio. Además de los atributos de los elementos, podemos pasar atributos y eventos específicos, como click o text.

Recomendado: FireQuery: Firebug optimizado para jQuery

Fuente | nettuts

Comentarios

Imagen de Juani00
Imagen de ajuarez
ajuarez

Excelente aporte, muchas gracias!!

Imagen de Jose Trezza
Imagen de Gamaliel
Gamaliel

excelentes tips, guardado en delicious por mi pesima memoria.

Imagen de luis - Compra Venta de Carros

Excelente tutorial que nos permite hacer más liviana nuestra pagina en cuanto a código.

Imagen de Luis Ventura
Luis Ventura

Buenos consejos... desde hace tiempo trabajo con jQuery y ha sido una gran utilidad para desarrollar mis proyectos.
Suerte

Imagen de Celestino Alcantara
Celestino Alcantara

gracias por el aporte, muy util.

Imagen de Leasti

No se porqué se ve todo el tiempo la frase "are block level" y no se puede ver nada. :(

Imagen de baluart
baluart

Hola Leasti, recién hemos actualizado el diseño del sitio y pueden haber desperfectos. Si encuentras otro por allí, no dejes de avisarnos. Gracias!

Imagen de Leasti

Gracias a vosotros por actualizarlo.

Saludos!

Tutoriales

Cómo descargar videos de VK.com
En este artículo voy a explicar como descargar videos y películas...
Descargar Facebook Móvil Gratis
Por si aún no lo han hecho, es posible descargar Facebook Móvil...
Cómo generar tráfico web con las redes sociales - Paso a Paso
Muchas empresas están publicando contenidos como la forma de crear...

Artículo Recomendado

3 Tips cruciales para recuperar archivos eliminados
¿Te imaginas perder el trabajo de toda una semana en tan solo unos segundos? Todos hemos pasado por este problema. Quizás eliminamos por error un archivo importante o lo borramos sin pensar que era valioso para otro... más