Perché definire una funzione anonima e passarla jQuery come argomento?


96

Sto esaminando l'eccellente codice demo peepcode dagli screencast di backbone.js. In esso, il codice backbone è tutto racchiuso in una funzione anonima che viene passata all'oggetto jQuery:

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

Nel mio codice backbone, ho appena inserito tutto il mio codice nell'evento jQuery DOM 'ready':

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

Qual è il punto / vantaggio del primo approccio? In questo modo viene creata una funzione anonima che viene quindi eseguita immediatamente con l'oggetto jQuery passato come argomento della funzione, assicurando effettivamente che $ sia l'oggetto jQuery. È questo l'unico punto: garantire che jQuery sia associato a "$" o ci sono altri motivi per farlo?


4
Dovresti invece aver esplorato SO prima.
Alexander

Interoperabilità con altre librerie: se l'autore della pagina deve usare $.noConflict(), il primo esempio funzionerà comunque.
DCoder

Possibile duplicato: jQuery e $ questions
Alexander

Vedi possibile duplicato di jQuery document.ready vs self calling anonymous function per la differenza
Bergi,

@ Alexander ma poi altre persone troveranno questa domanda prima su SO. :-)
caiosm1005

Risposte:


179

I due blocchi di codice che hai mostrato sono notevolmente diversi in quanto e perché vengono eseguiti. Non si escludono a vicenda. Non servono allo stesso scopo.

Moduli JavaScript


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

Questo è un pattern "JavaScript Module", implementato con una funzione che richiama immediatamente.

Lo scopo di questo codice è fornire "modularità", privacy e incapsulamento per il codice.

L'implementazione di questo è una funzione che viene immediatamente invocata dalla (jQuery)parentesi chiamante . Lo scopo del passaggio di jQuery tra parentesi è fornire lo scoping locale alla variabile globale. Ciò aiuta a ridurre la quantità di overhead per la ricerca della $variabile e in alcuni casi consente una migliore compressione / ottimizzazione per i minifiers.

Le funzioni invocate immediatamente vengono eseguite, beh, immediatamente. Non appena la definizione della funzione è completa, la funzione viene eseguita.

funzione "DOMReady" di jQuery

Questo è un alias della funzione "DOMReady" di jQuery: http://api.jquery.com/ready/


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

La funzione "DOMReady" di jQuery viene eseguita quando il DOM è pronto per essere manipolato dal codice JavaScript.

Moduli vs DOMReady nel codice Backbone

È una cattiva idea definire il codice Backbone all'interno della funzione DOMReady di jQuery e potenzialmente dannoso per le prestazioni dell'applicazione. Questa funzione non viene chiamata finché il DOM non è stato caricato ed è pronto per essere manipolato. Ciò significa che stai aspettando che il browser abbia analizzato il DOM almeno una volta prima di definire i tuoi oggetti.

È un'idea migliore definire gli oggetti Backbone al di fuori di una funzione DOMReady. Io, tra molti altri, preferisco farlo all'interno di un modello di modulo JavaScript in modo da poter fornire incapsulamento e privacy per il mio codice. Tendo a usare il modello "Revealing Module" (vedi il primo collegamento sopra) per fornire l'accesso ai bit di cui ho bisogno al di fuori del mio modulo.

Definendo i tuoi oggetti al di fuori della funzione DOMReady e fornendo un modo per fare riferimento ad essi, stai consentendo al browser di ottenere un vantaggio sull'elaborazione del tuo JavaScript, accelerando potenzialmente l'esperienza dell'utente. Inoltre rende il codice più flessibile in quanto puoi spostare le cose senza doversi preoccupare di creare più funzioni DOMREady quando sposti le cose.

Probabilmente utilizzerai una funzione DOMReady, comunque, anche se definisci i tuoi oggetti Backbone da qualche altra parte. Il motivo è che molte app Backbone devono manipolare il DOM in qualche modo. Per fare ciò, è necessario attendere che il DOM sia pronto, quindi è necessario utilizzare la funzione DOMReady per avviare l'applicazione dopo che è stata definita.

Puoi trovare molti esempi di questo in giro per il Web, ma ecco un'implementazione molto semplice, utilizzando sia un modulo che la funzione 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();
});

1
Grazie per questa risposta dettagliata. Sapevo della funzione DOMReady che chiamava solo quando è stato attivato l'evento DOM ready, ma non ho mai pensato che sarebbe stato un problema. Dividere il codice nella definizione dei bit della spina dorsale all'interno di un modulo e quindi interagire con essi nel dom ready sembra davvero l'approccio migliore
Matt Roberts

2
È interessante notare che l'app di esempio "todo" con backbone src mette tutto pronto nel dom.
Matt Roberts

2
Non dimenticare che il pattern del modulo javascript è anche chiamato IIFE.
Jess

1
le funzioni anonime vengono essenzialmente eseguite contemporaneamente al DOM ready, quindi come può renderle più efficienti?
bhavya_w

14

Come nota a margine minore, l'invio di $ come argomento a una funzione anonima rende $ locale a quella funzione che ha una piccola implicazione positiva sulle prestazioni se la funzione $ viene chiamata molto. Questo perché javascript cerca prima l'ambito locale per le variabili e poi lo attraversa fino all'ambito della finestra (dove $ di solito risiede).


9

Ti assicura di poter sempre utilizzare $all'interno di quella chiusura anche se$.noConflict() stata utilizzata.

Senza questa chiusura dovresti usare jQueryinvece di $tutto il tempo.



2

Usali entrambi.

La funzione di auto invocazione in cui passi jQuery per prevenire conflitti di libreria e per assicurarti che jQuery sia disponibile come ti aspetteresti con $.

E il metodo di scelta rapida .ready () come richiesto per eseguire javascript solo dopo che DOM è stato caricato:

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

    //and rest of code here
})(jQuery);

Una versione più breve che ho trovato altrove su SO (protegge anche undefined) :jQuery(function ($, undefined) { /* Code */ });
Jared Gotte
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.