Quels avantages l'utilisation (fonction (fenêtre, document, indéfini) {…}) (fenêtre, document) se confère-t-elle?

Je suppose que l'utilisation de ce modèle est la nouvelle chaleur, mais je ne comprends pas quel est l'avantage et je ne comprends pas les implications de la portée.

Le motif:

(function(window, document, undefined){ window.MyObject = { methodA: function() { ... }, methodB: function() { ... } }; })(window, document) 

J'ai donc plusieurs questions à ce sujet.

Existe-t-il un avantage particulier pour encapsuler un objet comme celui-ci?
Pourquoi la fenêtre et le document sont-ils alimentés au lieu d'être accédés normalement?
Pourquoi le diable est-il undefined ?
L'attachement de l'objet que nous créons-nous directement à la fenêtre est-il une bonne idée?

Je suis habitué à ce que j'appellerai le style Crockford de l'encapsulation Javascript (parce que je l'ai extrait des vidéos Javascript de Douglas Crockford).

 NameSpace.MyObject = function() { // Private methods // These methods are available in the closure // but are not exposed outside the object we'll be returning. var methodA = function() { ... }; // Public methods // We return an object that uses our private functions, // but only exposes the interface we want to be available. return { methodB: function() { var a = methodA(); }, methodC: function() { ... } } // Note that we're executing the function here. }(); 

L'un de ces modèles fonctionne-t-il mieux que l'autre? Le premier est-il l'évolution de l'autre?

Pourquoi la fenêtre et le document sont-ils alimentés au lieu d'être accédés normalement?

Généralement, pour sécuriser le processus de résolution des identificateurs, les avoir en tant que variables locales peuvent aider (bien que l'IMO puisse améliorer les performances).

Passer l'objet global est également une technique largement utilisée sur les environnements non navigateurs, où vous n'avez pas d'identificateur de window sur la portée globale, par exemple:

 (function (global) { //.. })(this); // this on the global execution context is // the global object itself 

Pourquoi le diable est-il indéfini?

Ceci est fait parce que la propriété globale undefined dans ECMAScript 3 est mutable, ce qui signifie que quelqu'un pourrait modifier sa valeur affectant votre code, par exemple:

 undefined = true; // mutable (function (undefined) { alert(typeof undefined); // "undefined", the local identifier })(); // <-- no value passed, undefined by default 

Si vous regardez avec précaution, undefined n'est en fait pas passé (il n'y a pas d'argument sur l'appel de fonction), c'est l'une des façons fiables d'obtenir la valeur undefined , sans utiliser la window.undefined propriété. window.undefined .

Le nom undefined en JavaScript ne signifie rien de spécial, n'est pas un mot-clé comme true , false , etc. … c'est juste un identifiant.

Juste pour mémoire, dans ECMAScript 5, cette propriété a été rendue impossible à écrire …

L'attachement de l'objet que nous créons-nous directement à la fenêtre est-il une bonne idée?

C'est une façon courante de déclarer les propriétés globales lorsque vous êtes sur une autre portée de la fonction.

Ce style particulier apporte des avantages sur le style "Crockford". Principalement, le passage de la window et du document permet de minimiser plus efficacement le script. Un minificateur peut renommer ces paramètres à des noms de caractères uniques, en économisant respectivement 5 et 7 octets par référence. Cela peut s'ajouter: jQuery fait référence à la window 33 fois et document 91 fois. La minimisation de chaque jeton à un caractère permet d'économiser 802 octets.

En outre, vous obtenez un avantage de vitesse d'exécution. Lorsque j'ai lu l' affirmation de @joekarl selon laquelle il offre un avantage pour la performance, je pensais que "cela semble plutôt parasite". J'ai donc profilé la performance réelle avec une page de test . window référencement cent millions de fois, la référence de la variable locale offre une augmentation modérée de 20% de la vitesse (4200 ms à 3400ms) dans Firefox 3.6 et une augmentation chocante de 31 000% (13 sec à 400ms) dans Chrome 9.

Bien sûr, vous n'allerez jamais à la window référence 100 000 000 fois en pratique, et même 10 000 références directes ne prennent que 1 ms dans Chrome, donc le gain réel de performance ici est presque totalement négligeable.

Pourquoi le diable est-il undefined ?

Parce que (tel que mentionné par @CMS ), le jeton undefined est en fait indéfini . Contrairement à null , il n'a pas de sens spécial, et vous pouvez attribuer gratuitement à cet identifiant comme n'importe quel autre nom de variable. (Notez cependant que cela n'est plus vrai dans ECMAScript 5 ).

L'attachement de l'objet que nous créons-nous directement à la fenêtre est-il une bonne idée?

L'objet de window est la portée globale, donc c'est exactement ce que vous faites à un moment donné, que vous n'exprimez pas explicitement "fenêtre". window.Namespace = {}; Et Namespace = {}; Sont équivalents.

Je suis avec vous en utilisant le style de Crockford.

Pour répondre à tes questions

1. Y a-t-il un avantage particulier à encapsuler un objet comme celui-ci?

Le seul avantage que je peux voir est de créer des fenêtres et de documenter des variables locales au lieu de variables globales, vous obtenez une sécurité ajoutée en ne pouvant pas écraser directement l'un ni l'autre et aussi un gain de performance par les deux étant local.

2. Pourquoi la fenêtre et le document sont-ils alimentés au lieu d'être accédés normalement?

Adresse ci-dessus. Les variables locales ont tendance à être plus rapides, mais avec jit compiling ces jours-ci devient nominal.

3. Pourquoi le pieu est-il indéfini?

Aucune idée….

4. Est-ce que l'objet que nous créons directement pour ouvrir une bonne idée est particulièrement bon?

Probablement pas, mais je resterais toujours avec le modèle de Crockford en attachant la fonction à l'objet fenêtre, l'expose au reste de la pile globale via l'objet fenêtre plutôt que de l'exposer à travers un espace de noms non standard.

Je pense que c'est principalement pour le code qui doit être exécuté dans plusieurs contextes de fenêtre. Disons que vous avez une application complexe avec beaucoup d'iframes et / ou de fenêtres enfant. Ils doivent tous exécuter le code dans MyObject, mais vous souhaitez simplement le charger une fois. Donc, vous le chargez dans n'importe quelle fenêtre / image que vous choisissez, mais vous créez un objet MyObject pour chaque fenêtre / cadre avec des références à la fenêtre et au document appropriés.

Prendre un argument indéfini tente de protéger contre le fait que indéfini peut être modifié:

 undefined = 3; alert(undefined); 

Voir la réponse de CMS sur la façon dont cela améliore la sécurité.