Warum eine anonyme Funktion definieren und jQuery als Argument übergeben?

96

Ich schaue mir den hervorragenden Peepcode-Demo-Code aus den Screencasts von backbone.js an. Darin ist der Backbone-Code in einer anonymen Funktion enthalten, die an das jQuery-Objekt übergeben wird:

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

In meinem eigenen Backbone-Code habe ich gerade meinen gesamten Code in das Ereignis "ready" von jQuery DOM eingeschlossen:

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

Was ist der Sinn / Vorteil des ersten Ansatzes? Auf diese Weise wird eine anonyme Funktion erstellt, die sofort ausgeführt wird, wobei das jQuery-Objekt als Funktionsargument übergeben wird, wodurch effektiv sichergestellt wird, dass $ das jQuery-Objekt ist. Ist dies der einzige Punkt, um sicherzustellen, dass jQuery an '$' gebunden ist, oder gibt es andere Gründe dafür?

Matt Roberts
quelle
4
Sie sollten stattdessen zuerst SO durchsucht haben.
Alexander
Interoperabilität mit anderen Bibliotheken - Wenn der Seitenautor diese verwenden muss, $.noConflict()funktioniert das erste Beispiel weiterhin.
DCoder
Mögliches Duplikat: jQuery und $ Fragen
Alexander
Siehe mögliche doppelte jQuery document.ready vs selbst aufrufende anonyme Funktion für den Unterschied
Bergi
@ Alexander, aber dann werden andere Leute diese Frage zuerst auf SO finden. :-)
caiosm1005

Antworten:

179

Die beiden von Ihnen gezeigten Codeblöcke unterscheiden sich erheblich darin, wann und warum sie ausgeführt werden. Sie schließen sich nicht aus. Sie dienen nicht dem gleichen Zweck.

JavaScript-Module


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

Dies ist ein "JavaScript-Modul" -Muster, das mit einer sofort aufrufenden Funktion implementiert wird.

Der Zweck dieses Codes besteht darin, "Modularität", Datenschutz und Kapselung für Ihren Code bereitzustellen.

Die Implementierung ist eine Funktion, die sofort von der aufrufenden (jQuery)Klammer aufgerufen wird . Der Zweck der Übergabe von jQuery an die Klammer besteht darin, der globalen Variablen einen lokalen Gültigkeitsbereich bereitzustellen. Dies trägt dazu bei, den Aufwand $für das Nachschlagen der Variablen zu verringern , und ermöglicht in einigen Fällen eine bessere Komprimierung / Optimierung für Minifizierer.

Sofort aufrufende Funktionen werden sofort ausgeführt. Sobald die Funktionsdefinition abgeschlossen ist, wird die Funktion ausgeführt.

jQuerys "DOMReady" -Funktion

Dies ist ein Alias ​​für die "DOMReady" -Funktion von jQuery: http://api.jquery.com/ready/


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

Die "DOMReady" -Funktion von jQuery wird ausgeführt, wenn das DOM bereit ist, von Ihrem JavaScript-Code bearbeitet zu werden.

Module vs DOMReady im Backbone-Code

Es ist eine schlechte Form, Ihren Backbone-Code innerhalb der DOMReady-Funktion von jQuery zu definieren, was möglicherweise die Leistung Ihrer Anwendung beeinträchtigt. Diese Funktion wird erst aufgerufen, wenn das DOM geladen wurde und zur Bearbeitung bereit ist. Das heißt, Sie warten mindestens einmal, bis der Browser das DOM analysiert hat, bevor Sie Ihre Objekte definieren.

Es ist besser, Ihre Backbone-Objekte außerhalb einer DOMReady-Funktion zu definieren. Ich bevorzuge es unter anderem, dies innerhalb eines JavaScript-Modulmusters zu tun, damit ich meinen Code kapseln und schützen kann. Ich verwende normalerweise das Muster "Revealing Module" (siehe den ersten Link oben), um Zugriff auf die Bits zu erhalten, die ich außerhalb meines Moduls benötige.

Indem Sie Ihre Objekte außerhalb der DOMReady-Funktion definieren und eine Möglichkeit bieten, auf sie zu verweisen, können Sie dem Browser einen Vorsprung bei der Verarbeitung Ihres JavaScript verschaffen, was möglicherweise die Benutzererfahrung beschleunigt. Es macht den Code auch flexibler, da Sie Dinge verschieben können, ohne sich darum kümmern zu müssen, mehr DOMREady-Funktionen zu erstellen, wenn Sie Dinge verschieben.

Sie werden wahrscheinlich trotzdem eine DOMReady-Funktion verwenden, selbst wenn Sie Ihre Backbone-Objekte an einer anderen Stelle definieren. Der Grund ist, dass viele Backbone-Apps das DOM auf irgendeine Weise manipulieren müssen. Dazu müssen Sie warten, bis das DOM bereit ist. Daher müssen Sie die DOMReady-Funktion verwenden, um Ihre Anwendung zu starten, nachdem sie definiert wurde.

Sie können viele Beispiele dafür im Internet finden, aber hier ist eine sehr grundlegende Implementierung, die sowohl ein Modul als auch die DOMReady-Funktion verwendet:



// 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
quelle
1
Vielen Dank für diese ausführliche Antwort. Ich wusste, dass die DOMReady-Funktion nur aufgerufen wird, wenn das DOM-fähige Ereignis ausgelöst wird, hätte aber nie gedacht, dass dies ein Problem sein würde. Die Aufteilung des Codes in die Definition der Backbone-Bits innerhalb eines Moduls und die anschließende Interaktion mit ihnen im Dom Ready scheint in der Tat der beste Ansatz zu sein
Matt Roberts,
2
Interessanterweise stellt die "todo" -Beispiel-App mit dem Backbone src alles im Dom bereit.
Matt Roberts
2
Vergessen Sie nicht, dass das Javascript-Modulmuster auch als bezeichnet wird IIFE.
Jess
1
Anonyme Funktionen werden im Wesentlichen gleichzeitig mit DOM-fähigen Funktionen ausgeführt. Wie werden sie effizienter?
Bhavya_w
14

Als kleine Nebenbemerkung macht das Senden von $ als Argument an eine anonyme Funktion $ lokal für diese Funktion, die eine kleine positive Auswirkung auf die Leistung hat, wenn die $ -Funktion häufig aufgerufen wird. Dies liegt daran, dass Javascript zuerst den lokalen Bereich nach Variablen durchsucht und dann bis zum Fensterbereich (wo $ normalerweise lebt) durchläuft.

joidegn
quelle
9

Es stellt sicher , Sie können immer verwenden $innerhalb dieser Schließung selbst wenn $.noConflict()verwendet wurde.

Ohne diesen Verschluss sollten Sie jQueryanstelle $der gesamten Zeit verwenden.

DiebMaster
quelle
4

Damit soll ein möglicher Konflikt der Variablen $ vermieden werden. Wenn etwas anderes eine Variable namens $ definiert, verwendet Ihr Plugin möglicherweise die falsche Definition

Weitere Informationen finden Sie unter http://docs.jquery.com/Plugins/Authoring#Getting_Started

Andrew Brock
quelle
2

Verwende beide.

Die selbstaufrufende Funktion, mit der Sie jQuery übergeben, um Bibliothekskonflikte zu vermeiden und um sicherzustellen, dass jQuery verfügbar ist, wie Sie es mit $ erwarten würden.

Und die Verknüpfungsmethode .ready (), die erforderlich ist, um Javascript erst auszuführen, nachdem DOM geladen wurde:

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

    //and rest of code here
})(jQuery);
Andrew
quelle
Eine kürzere Version, die ich an anderer Stelle auf SO gefunden habe (schützt auch undefiniert) :jQuery(function ($, undefined) { /* Code */ });
Jared Gotte