¿Por qué definir una función anónima y pasarla jQuery como argumento?

96

Estoy revisando el excelente código de demostración de peepcode de los screencasts de backbone.js. En él, el código de la red troncal está encerrado en una función anónima que se pasa al objeto jQuery:

(function($) {
  // Backbone code in here
})(jQuery);

En mi propio código de red troncal, acabo de envolver todo mi código en el evento jQuery DOM 'ready':

$(function(){
  // Backbone code in here
});

¿Cuál es el punto / la ventaja del primer enfoque? Al hacerlo de esta manera, se crea una función anónima que luego se ejecuta inmediatamente con el objeto jQuery que se pasa como argumento de la función, asegurando efectivamente que $ es el objeto jQuery. ¿Es este el único punto: garantizar que jQuery esté vinculado a '$' o hay otras razones para hacer esto?

Matt Roberts
fuente
4
En su lugar, debería haber navegado SO primero.
Alexander
Interoperabilidad con otras bibliotecas: si el autor de la página necesita usar $.noConflict(), el primer ejemplo seguirá funcionando.
DCoder
Posible duplicado: jQuery y $ preguntas
Alexander
Ver posible duplicado jQuery document.ready vs función anónima de auto-llamada para la diferencia
Bergi
@Alexander, pero luego otras personas encontrarán esta pregunta en SO primero. :-)
caiosm1005

Respuestas:

179

Los dos bloques de código que ha mostrado son dramáticamente diferentes en cuándo y por qué se ejecutan. No son exclusivos el uno del otro. No tienen el mismo propósito.

Módulos JavaScript


(function($) {
  // Backbone code in here
})(jQuery);

Este es un patrón de "Módulo JavaScript", implementado con una función de invocación inmediata.

El propósito de este código es proporcionar "modularidad", privacidad y encapsulación para su código.

La implementación de esto es una función que es inmediatamente invocada por el (jQuery)paréntesis de llamada . El propósito de pasar jQuery entre paréntesis es proporcionar un alcance local a la variable global. Esto ayuda a reducir la sobrecarga de buscar el$ variable y permite una mejor compresión / optimización para los minificadores en algunos casos.

Las funciones de invocación inmediata se ejecutan, bueno, de inmediato. Tan pronto como se completa la definición de la función, la función se ejecuta.

Función "DOMReady" de jQuery

Este es un alias de la función "DOMReady" de jQuery: http://api.jquery.com/ready/


$(function(){
  // Backbone code in here
});

La función "DOMReady" de jQuery se ejecuta cuando el DOM está listo para ser manipulado por su código JavaScript.

Módulos vs DOMReady en código backbone

Es una mala forma definir su código Backbone dentro de la función DOMReady de jQuery, y potencialmente perjudicial para el rendimiento de su aplicación. Esta función no se llama hasta que el DOM se ha cargado y está listo para ser manipulado. Eso significa que está esperando hasta que el navegador haya analizado el DOM al menos una vez antes de definir sus objetos.

Es una mejor idea definir sus objetos Backbone fuera de una función DOMReady. Yo, entre muchos otros, prefiero hacer esto dentro de un patrón de módulo JavaScript para poder proporcionar encapsulación y privacidad para mi código. Tiendo a usar el patrón "Módulo revelador" (ver el primer enlace arriba) para proporcionar acceso a los bits que necesito fuera de mi módulo.

Al definir sus objetos fuera de la función DOMReady y proporcionar alguna forma de referenciarlos, está permitiendo que el navegador obtenga una ventaja en el procesamiento de su JavaScript, lo que potencialmente acelera la experiencia del usuario. También hace que el código sea más flexible ya que puede mover cosas sin tener que preocuparse por crear más funciones DOMREady cuando mueva cosas.

Es probable que use una función DOMReady, incluso si define sus objetos Backbone en otro lugar. La razón es que muchas aplicaciones Backbone necesitan manipular el DOM de alguna manera. Para hacer esto, debe esperar hasta que DOM esté listo, por lo tanto, debe usar la función DOMReady para iniciar su aplicación después de que se haya definido.

Puede encontrar muchos ejemplos de esto en la web, pero aquí hay una implementación muy básica, usando tanto un Módulo como la función DOMReady:



// Define "MyApp" as a revealing module

MyApp = (function(Backbone, $){

  var View = Backbone.View.extend({
    // do stuff here  
  });

  return {
    init: function(){
      var view = new View();
      $("#some-div").html(view.render().el);
    }
  };

})(Backbone, jQuery);



// Run "MyApp" in DOMReady

$(function(){
  MyApp.init();
});
Derick Bailey
fuente
1
Gracias por esta respuesta detallada. Sabía que la función DOMReady solo llamaba cuando se activaba el evento DOM Ready, pero nunca pensé que eso sería un problema. Dividir el código para definir los bits de la red troncal dentro de un módulo y luego interactuar con ellos en el dom ready parece ser el mejor enfoque
Matt Roberts
2
Curiosamente, la aplicación de ejemplo "todo" con el backbone src pone todo en el dom listo.
Matt Roberts
2
No olvide que el patrón del módulo javascript también se llama IIFE.
Jess
1
Las funciones anónimas se ejecutan esencialmente al mismo tiempo que DOM ready, entonces, ¿cómo las hace más eficientes?
bhavya_w
14

Como nota al margen menor, enviar $ como argumento a una función anónima hace que $ sea local para esa función, lo que tiene una pequeña implicación positiva en el rendimiento si la función $ se llama mucho. Esto se debe a que javascript busca variables en el ámbito local primero y luego recorre todo el camino hasta el ámbito de la ventana (donde normalmente vive $).

joidegn
fuente
9

Asegura que siempre pueda usar $dentro de ese cierre, incluso si $.noConflict()se usó.

Sin este cierre, se suponía que usarías en jQuerylugar de $todo el tiempo.

ThiefMaster
fuente
2

Utilice ambos.

La función de auto invocación en la que pasa jQuery para evitar conflictos de biblioteca y para asegurarse de que jQuery esté disponible como es de esperar con $.

Y el método de acceso directo .ready () según sea necesario para ejecutar javascript solo después de que DOM se haya cargado:

(function($) {
    $(function(){
          //add code here that needs to wait for page to be loaded
    });

    //and rest of code here
})(jQuery);
Andrés
fuente
Una versión más corta que encontré en otro lugar de SO (también protege indefinido) :jQuery(function ($, undefined) { /* Code */ });
Jared Gotte