Por que definir uma função anônima e passar jQuery como o argumento?

96

Estou examinando o excelente código de demonstração do peepcode nos screencasts do backbone.js. Nele, o código de backbone está todo fechado em uma função anônima que é passada ao objeto jQuery:

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

Em meu próprio código de backbone, acabei de envolver todo o meu código no evento 'pronto' do DOM jQuery:

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

Qual é o ponto / vantagem da primeira abordagem? Fazer isso dessa forma cria uma função anônima que é executada imediatamente com o objeto jQuery sendo passado como o argumento da função, garantindo efetivamente que $ seja o objeto jQuery. Este é o único ponto - para garantir que o jQuery está vinculado a '$' ou existem outras razões para fazer isso?

Matt Roberts
fonte
4
Você deveria ter navegado SO primeiro em vez disso.
Alexander
Interoperabilidade com outras bibliotecas - se o autor da página precisar usar $.noConflict(), o primeiro exemplo ainda funcionará.
DCoder
Possível duplicata: jQuery e $ questions
Alexander
Veja a possível duplicata da função jQuery document.ready vs função de chamada anônima para a diferença
Bergi
@Alexander, mas outras pessoas encontrarão essa pergunta no SO primeiro. :-)
caiosm1005

Respostas:

179

Os dois blocos de código que você mostrou são dramaticamente diferentes em quando e por que são executados. Eles não são exclusivos um do outro. Eles não têm o mesmo propósito.

Módulos JavaScript


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

Este é um padrão de "Módulo JavaScript", implementado com uma função de chamada imediata.

O objetivo deste código é fornecer "modularidade", privacidade e encapsulamento para o seu código.

A implementação disso é uma função que é imediatamente invocada pelo (jQuery)parêntese de chamada . O objetivo de passar jQuery para o parêntese é fornecer escopo local para a variável global. Isso ajuda a reduzir a quantidade de sobrecarga de pesquisa da $variável e permite uma melhor compactação / otimização para minificadores em alguns casos.

As funções de invocação imediata são executadas, bem, imediatamente. Assim que a definição da função for concluída, a função será executada.

Função "DOMReady" do jQuery

Este é um alias para a função "DOMReady" do jQuery: http://api.jquery.com/ready/


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

A função "DOMReady" do jQuery é executada quando o DOM está pronto para ser manipulado por seu código JavaScript.

Módulos vs DOMReady no código de backbone

É péssimo definir seu código de Backbone dentro da função DOMReady do jQuery, e potencialmente prejudicial ao desempenho de seu aplicativo. Esta função não é chamada até que o DOM seja carregado e esteja pronto para ser manipulado. Isso significa que você está esperando até que o navegador tenha analisado o DOM pelo menos uma vez antes de definir seus objetos.

É uma ideia melhor definir seus objetos Backbone fora de uma função DOMReady. Eu, entre muitos outros, prefiro fazer isso dentro de um padrão de módulo JavaScript para poder fornecer encapsulamento e privacidade para meu código. Costumo usar o padrão "Módulo revelador" (consulte o primeiro link acima) para fornecer acesso aos bits que preciso fora do meu módulo.

Ao definir seus objetos fora da função DOMReady e fornecer alguma maneira de referenciá-los, você está permitindo que o navegador obtenha uma vantagem no processamento de seu JavaScript, potencialmente acelerando a experiência do usuário. Isso também torna o código mais flexível, pois você pode mover coisas sem ter que se preocupar em criar mais funções DOMREady ao mover as coisas.

Você provavelmente vai usar uma função DOMReady, ainda, mesmo se definir seus objetos de Backbone em outro lugar. O motivo é que muitos aplicativos de Backbone precisam manipular o DOM de alguma maneira. Para fazer isso, você precisa esperar até que o DOM esteja pronto, portanto, você precisa usar a função DOMReady para iniciar seu aplicativo após ele ter sido definido.

Você pode encontrar muitos exemplos disso na web, mas aqui está uma implementação muito básica, usando um módulo e a função 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
fonte
1
Obrigado por esta resposta detalhada. Eu sabia sobre a função DOMReady chamando apenas quando o evento pronto do DOM disparava, mas nunca pensei que isso seria um problema. Dividir o código para definir os bits de backbone dentro de um módulo e, em seguida, interagir com eles no dom pronto realmente parece ser a melhor abordagem
Matt Roberts
2
Curiosamente, o aplicativo de exemplo "todo" com o backbone src coloca tudo pronto no dom.
Matt Roberts
2
Não se esqueça que o padrão de módulo javascript também é chamado de IIFE.
Jess de
1
funções anônimas são essencialmente executadas ao mesmo tempo que o DOM está pronto, então como isso as torna mais eficientes ??
bhavya_w
14

Como nota secundária, enviar $ como um argumento para uma função anônima torna $ local para aquela função que tem uma pequena implicação de desempenho positivo se a função $ for muito chamada. Isso ocorre porque o javascript procura primeiro as variáveis ​​no escopo local e depois desce até o escopo da janela (onde $ geralmente reside).

Joidegn
fonte
9

Isso garante que você sempre possa usar $dentro dessa tampa, mesmo que tenha $.noConflict()sido usada.

Sem este encerramento você estaria supostamente para usar jQueryem vez de $todo o tempo.

ThiefMaster
fonte
2

Use ambos.

A função de auto-chamada na qual você passa o jQuery para evitar conflitos de biblioteca e apenas para garantir que o jQuery esteja disponível como você esperaria com $.

E o método de atalho .ready () conforme necessário para executar o javascript somente depois que o DOM for carregado:

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

    //and rest of code here
})(jQuery);
Andrew
fonte
Uma versão mais curta que encontrei em outro lugar no SO (também protege undefined) :jQuery(function ($, undefined) { /* Code */ });
Jared Gotte