Pourquoi définir une fonction anonyme et lui passer jQuery comme argument?

98

Je regarde l'excellent code de démonstration peepcode des screencasts backbone.js. Dans celui-ci, le code de la dorsale est tout inclus dans une fonction anonyme à laquelle est passé l'objet jQuery:

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

Dans mon propre code de base, je viens d'encapsuler tout mon code dans l'événement jQuery DOM 'ready':

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

Quel est le point / avantage de la première approche? Cela crée une fonction anonyme qui est ensuite exécutée immédiatement avec l'objet jQuery passé en tant qu'argument de fonction, garantissant ainsi que $ est l'objet jQuery. Est-ce le seul point - pour garantir que jQuery est lié à '$' ou y a-t-il d'autres raisons de le faire?

Matt Roberts
la source
4
Vous devriez avoir parcouru SO en premier lieu.
Alexander
Interopérabilité avec d'autres bibliothèques - si l'auteur de la page doit utiliser $.noConflict(), le premier exemple fonctionnera toujours.
DCoder
Double possible: jQuery et $ questions
Alexander
Voir la possible copie de jQuery document.ready vs fonction anonyme d'auto-appel pour la différence
Bergi
@Alexander mais d'autres personnes trouveront d'abord cette question sur SO. :-)
caiosm1005

Réponses:

182

Les deux blocs de code que vous avez montrés sont très différents quant au moment et à la raison de leur exécution. Ils ne sont pas exclusifs l'un de l'autre. Ils ne servent pas le même objectif.

Modules JavaScript


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

Il s'agit d'un modèle de "module JavaScript", implémenté avec une fonction d'appel immédiate.

Le but de ce code est de fournir "modularité", confidentialité et encapsulation pour votre code.

L'implémentation de ceci est une fonction qui est immédiatement appelée par la (jQuery)parenthèse appelante . Le but de passer jQuery entre parenthèses est de fournir une portée locale à la variable globale. Cela permet de réduire la surcharge de recherche de la $variable et permet une meilleure compression / optimisation des minificateurs dans certains cas.

Les fonctions qui invoquent immédiatement sont exécutées, enfin, immédiatement. Dès que la définition de la fonction est terminée, la fonction est exécutée.

Fonction "DOMReady" de jQuery

Ceci est un alias de la fonction "DOMReady" de jQuery: http://api.jquery.com/ready/


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

La fonction "DOMReady" de jQuery s'exécute lorsque le DOM est prêt à être manipulé par votre code JavaScript.

Modules vs DOMReady dans le code backbone

C'est une mauvaise forme de définir votre code Backbone à l'intérieur de la fonction DOMReady de jQuery, et potentiellement dommageable pour les performances de votre application. Cette fonction n'est appelée que lorsque le DOM est chargé et prêt à être manipulé. Cela signifie que vous attendez que le navigateur ait analysé le DOM au moins une fois avant de définir vos objets.

Il est préférable de définir vos objets Backbone en dehors d'une fonction DOMReady. Je préfère, parmi beaucoup d'autres, le faire à l'intérieur d'un modèle de module JavaScript afin de pouvoir fournir l'encapsulation et la confidentialité de mon code. J'ai tendance à utiliser le modèle "Revealing Module" (voir le premier lien ci-dessus) pour donner accès aux bits dont j'ai besoin en dehors de mon module.

En définissant vos objets en dehors de la fonction DOMReady et en fournissant un moyen de les référencer, vous permettez au navigateur de prendre une longueur d'avance sur le traitement de votre JavaScript, ce qui accélère potentiellement l'expérience utilisateur. Cela rend également le code plus flexible car vous pouvez déplacer des choses sans avoir à vous soucier de créer plus de fonctions DOMREady lorsque vous déplacez des choses.

Vous allez probablement utiliser une fonction DOMReady, même si vous définissez vos objets Backbone ailleurs. La raison en est que de nombreuses applications Backbone doivent manipuler le DOM d'une manière ou d'une autre. Pour ce faire, vous devez attendre que le DOM soit prêt, vous devez donc utiliser la fonction DOMReady pour démarrer votre application une fois qu'elle a été définie.

Vous pouvez trouver de nombreux exemples de cela sur le Web, mais voici une implémentation très basique, utilisant à la fois un module et la fonction 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
la source
1
Merci pour cette réponse détaillée. Je savais que la fonction DOMReady n'appelait que lorsque l'événement DOM ready était déclenché, mais je n'avais jamais vraiment pensé que ce serait un problème. Diviser le code en définissant les bits de l'épine dorsale à l'intérieur d'un module, puis interagir avec eux dans le dom ready semble en effet être la meilleure approche
Matt Roberts
2
Fait intéressant, l'application d'exemple "todo" avec le backbone src met tout dans le dom prêt.
Matt Roberts
2
N'oubliez pas que le modèle de module javascript est également appelé un IIFE.
Jess
1
les fonctions anonymes sont essentiellement exécutées en même temps que DOM ready, alors comment les rendre plus efficaces
bhavya_w
14

En guise de remarque mineure, l'envoi de $ comme argument à une fonction anonyme rend $ local à cette fonction, ce qui a une petite implication positive sur les performances si la fonction $ est appelée beaucoup. Cela est dû au fait que javascript recherche d'abord les variables dans la portée locale, puis descend jusqu'à la portée de la fenêtre (où $ vit généralement).

joidegn
la source
9

Cela garantit que vous pouvez toujours utiliser à l' $intérieur de cette fermeture même si elle a $.noConflict()été utilisée.

Sans cette fermeture, vous seriez censé utiliser jQueryau lieu de $tout le temps.

ThiefMaster
la source
4

C'est pour éviter un conflit potentiel de la variable $. Si quelque chose d'autre définit une variable nommée $, votre plugin peut utiliser la mauvaise définition

Reportez-vous à http://docs.jquery.com/Plugins/Authoring#Getting_Started pour plus de détails

Andrew Brock
la source
2

Utilise les deux.

La fonction d'auto-appel dans laquelle vous passez dans jQuery pour éviter les conflits de bibliothèque et pour vous assurer simplement que jQuery est disponible comme vous vous en doutez avec $.

Et la méthode de raccourci .ready () requise pour exécuter javascript uniquement après le chargement du DOM:

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

    //and rest of code here
})(jQuery);
Andrew
la source
Une version plus courte que j'ai trouvée ailleurs sur SO (protège également undefined) :jQuery(function ($, undefined) { /* Code */ });
Jared Gotte