161 votes

Comment fonctionne la syntaxe JavaScript/jQuery suivante : (function( window, undefined ) { })(window) ?

Avez-vous déjà jeté un coup d'œil sous le capot de l'appareil ? jQuery 1.4 et j'ai remarqué que le code source est encapsulé de la manière suivante :

(function( window, undefined ) {

  //All the JQuery code here 
  ...

})(window);

J'ai lu un article sur Espaces de noms JavaScript et un autre appelé " Une paire de parens importante donc je sais un peu ce qui se passe ici.

Mais je n'ai jamais vu cette syntaxe particulière auparavant. Quelle est cette undefined fait là-bas ? Et pourquoi est-ce que window doivent être passés et réapparaître à la fin ?

3 votes

Je voulais ajouter que Paul Irish en parle dans cette vidéo : paulirish.com/2010/10-choses-que-j'ai-appris-de-la-source-jquery

0 votes

@Bergi vous avez marqué ma question comme étant un doublon d'une autre mais j'ai posé la question presque un an avant le doublon. La distribution devrait être l'inverse.

0 votes

@dkinzer : Il ne s'agit pas d'être interrogé plus tôt, il s'agit de la meilleure réponse. Certes, dans ce cas, c'est au coude à coude, mais j'ai trouvé que la réponse de CMS était la meilleure. Venez à chat.stackoverflow.com/rooms/17 pour en discuter, cependant

165voto

Vincent Points 2354

L'indéfini est une variable normale et peut être changé simplement avec undefined = "new value"; . Ainsi, jQuery crée une variable locale "undefined" qui est VRAIMENT indéfinie.

La variable de la fenêtre est rendue locale pour des raisons de performance. En effet, lorsque JavaScript recherche une variable, il passe d'abord par les variables locales jusqu'à ce qu'il trouve le nom de la variable. S'il ne le trouve pas, JavaScript passe par la portée suivante, etc. jusqu'à ce qu'il filtre les variables globales. Ainsi, si la variable de la fenêtre est rendue locale, JavaScript peut la rechercher plus rapidement. Plus d'informations : Accélérez votre JavaScript - Nicholas C. Zakas

1 votes

Merci ! C'était une vidéo très instructive. Je pense que vous devez modifier votre réponse pour dire "la variable de la fenêtre est rendue locale". Je pense que c'est la meilleure réponse. J'ai compté et trouvé que l'objet window est appelé au moins 17 fois dans le code source de JQuery. Il doit donc y avoir un effet significatif dans le déplacement de la fenêtre dans le Local Scope.

0 votes

@DKinzer Oh oui, vous avez raison, bien sûr que c'est fabriqué localement. Heureux d'avoir pu vous aider =)

1 votes

Selon ce test actualisé jsperf.com/short-scope/5 Le passage par 'window' est en fait plus lent, lorsqu'il s'agit d'obtenir une fenêtre constante par le biais de jQuery, et particulièrement mauvais pour Safari. Donc, bien que 'undefined' ait une utilité, je ne suis pas convaincu que 'window' soit particulièrement utile dans tous les cas.

55voto

Box9 Points 41987

Indéfini

En déclarant undefined en tant qu'argument, mais sans jamais lui transmettre de valeur, garantit qu'elle est toujours indéfinie, car il s'agit simplement d'une variable dans la portée globale qui peut être écrasée. Cela rend a === undefined une alternative sûre à typeof a == 'undefined' ce qui permet de gagner quelques caractères. Cela rend également le code plus facile à minifier, puisque undefined peut être raccourci en u par exemple, en économisant quelques caractères supplémentaires.

Fenêtre

Passing window comme argument conserve une copie dans la portée locale, ce qui affecte les performances : http://jsperf.com/short-scope . Tous les accès à window devra désormais remonter un niveau de moins dans la chaîne des responsabilités. Comme pour undefined une copie locale permet à nouveau une minification plus agressive.


Sidenote :

Bien que cela n'ait pas été l'intention des développeurs de jQuery, le fait de passer en window permet à la bibliothèque d'être plus facilement intégrée dans des environnements Javascript côté serveur, par exemple node.js - où il n'y a pas de window objet. Dans une telle situation, une seule ligne doit être modifiée pour remplacer l'objet window avec un autre objet. Dans le cas de jQuery, un objet fantaisie window peut être créé et transmis dans le but de faire du scraping HTML (une bibliothèque telle que jsdom peut le faire).

2 votes

+1 pour avoir mentionné la minification, j'aimerais pouvoir +2 pour le jsperf -- La version minifiée est (function(a,b){})(window); -- a y b sont beaucoup plus courtes que window y undefined :)

0 votes

+1 J'avais entendu parler de chaîne de mesure avant, mais j'ai oublié le terme. Merci.

0 votes

C'est également une alternative à l'utilisation de void(0) qui a été conçue pour la même raison : void(0) est un moyen sûr d'obtenir la valeur indéfinie.

16voto

Chetan Sastry Points 14742

D'autres ont expliqué undefined . undefined est comme une variable globale qui peut être redéfinie à n'importe quelle valeur. Cette technique permet d'éviter que toutes les vérifications d'indéfinition ne se brisent si quelqu'un écrivait par exemple , undefined = 10 quelque part. Un argument qui n'est jamais passé est garanti comme étant réel. undefined quelle que soit la valeur de la variable undefined .

La raison de passer la fenêtre peut être illustrée par l'exemple suivant.

(function() {
   console.log(window);
   ...
   ...
   ...
   var window = 10;
})();

Qu'est-ce que la console enregistre ? La valeur de window objet droit ? Faux ! 10 ? Faux ! Il enregistre undefined . L'interpréteur Javascript (ou le compilateur JIT) le réécrit de cette manière : -.

(function() {
   var window; //and every other var in this function

   console.log(window);
   ...
   ...
   ...
   window = 10;

})();

Cependant, si vous obtenez le window comme argument, il n'y a pas de var et donc pas de surprise.

Je ne sais pas si jQuery le fait, mais si vous redéfinissez window une variable locale n'importe où dans votre fonction pour n'importe quelle raison, c'est une bonne idée de l'emprunter à la portée globale.

6voto

Nick Craver Points 313913

window est transmis comme ça, juste au cas où quelqu'un déciderait de redéfinir l'objet fenêtre dans IE, je suppose qu'il en va de même pour l'objet undefined au cas où il serait réaffecté d'une manière ou d'une autre plus tard.

Le sommet window dans la mesure où script ne fait que nommer l'argument "window", un argument plus local que l'argument global "window". window et c'est ce que le code à l'intérieur de cette fermeture va utiliser. Le site window à la fin spécifie en fait ce qu'il faut passer comme premier argument, dans ce cas la signification actuelle de window ...l'espoir est que vous n'avez pas foiré window avant que cela n'arrive.

Il est peut-être plus facile d'y penser en montrant le cas le plus typique utilisé dans jQuery, le plugin .noConflict() donc pour la majorité du code vous pouvez toujours utiliser $ même si cela signifie quelque chose autre que jQuery en dehors de ce champ d'application :

(function($) {
  //inside here, $ == jQuery, it was passed as the first argument
})(jQuery);

0 votes

Merci. Cela a beaucoup de sens. Cependant, je pense que la réponse est une combinaison de ceci et de ce que @C.Zakas dit.

0 votes

@DKinzer J'ai bien peur de ne pas être C. Zakas ;)

0 votes

@Vincent, désolé pour ça :-)

5voto

Semra Points 371

Testé avec 1000000 itérations. Ce type de localisation n'a eu aucun effet sur les performances. Pas même une seule milliseconde sur 1000000 itérations. C'est tout simplement inutile.

2 votes

Sans oublier que la fermeture transporte toutes les variables avec l'instance de la fonction, donc si vous avez 100 octets dans la fermeture, et 1000 instances, cela représente 100kb de mémoire supplémentaire.

0 votes

@AkashKava et @Semra, je ne pense pas que ce test tienne vraiment compte de la raison pour laquelle vous passeriez par la fenêtre dans une situation réelle. Le gain de performance ne sera visible que si vous avez des closures profondément imbriquées qui accèdent à cette variable plus loin dans la chaîne de portée. évidemment, si votre fonction n'est qu'à une étape de la chaîne de portée de la variable, vous ne verrez pas beaucoup de gain. mais si elle était tout en bas et qu'elle devait obtenir window vous pourriez voir un gain par une copie locale.

0 votes

@gabereal les nouveaux moteurs JavaScript résolvent les fermetures au moment de la compilation elle-même, il n'y a pas de gain de performance dans la fermeture au moment de l'exécution. Je doute qu'il y ait un gain de performance mesurable, si vous êtes si confiant, vous pouvez créer un exemple jsperf pour démontrer la performance. La seule performance que nous obtenons est en isolant les fermetures qui résulte en une meilleure minification qui réduit la taille et la performance est obtenue par un téléchargement et un parsing plus rapide du script.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X