J'ai lu beaucoup de Javascript récemment et j'ai remarqué que le fichier entier est enveloppé comme suit dans les fichiers .js à importer.
(function() {
...
code
...
})();
Quelle est la raison de cela plutôt qu'un simple ensemble de fonctions constructeurs?
javascript
scope
coding-style
iife
Andrew Kou
la source
la source
Réponses:
C'est généralement pour nommer (voir plus loin) et contrôler la visibilité des fonctions membres et / ou des variables. Considérez-le comme une définition d'objet. Son nom technique est une expression de fonction immédiatement invoquée (IIFE). Les plugins jQuery sont généralement écrits comme ceci.
En Javascript, vous pouvez imbriquer des fonctions. Donc, ce qui suit est légal:
Vous pouvez maintenant appeler
outerFunction()
, mais la visibilité deinnerFunction()
est limitée à la portée deouterFunction()
, ce qui signifie qu'il est privé deouterFunction()
. Il suit essentiellement le même principe que les variables en Javascript:En conséquence:
Dans le scénario ci-dessus, vous pouvez appeler
globalFunction()
de n'importe où, mais vous ne pouvez pas appelerlocalFunction1
oulocalFunction2
.Ce que vous faites lorsque vous écrivez
(function() { ... })()
, c'est que vous faites du code à l'intérieur du premier ensemble de parenthèses une fonction littérale (ce qui signifie que tout "l'objet" est en fait une fonction). Après cela, vous invoquez automatiquement la fonction (la dernière()
) que vous venez de définir. Donc, le principal avantage de cela, comme je l'ai mentionné précédemment, est que vous pouvez avoir des méthodes / fonctions et propriétés privées:Dans le premier exemple, vous invoqueriez explicitement
globalFunction
par nom pour l'exécuter. Autrement dit, vous feriez justeglobalFunction()
pour l'exécuter. Mais dans l'exemple ci-dessus, vous ne définissez pas seulement une fonction; vous le définissez et l' invoquez en une seule fois. Cela signifie que lorsque le fichier JavaScript est chargé, il est immédiatement exécuté. Bien sûr, vous pourriez faire:Le comportement serait en grande partie le même, sauf pour une différence significative: vous évitez de polluer la portée globale lorsque vous utilisez un IIFE (en conséquence, cela signifie également que vous ne pouvez pas invoquer la fonction plusieurs fois car elle n'a pas de nom, mais puisque cette fonction est uniquement destinée à être exécutée une fois que ce n'est vraiment pas un problème).
La chose intéressante avec les IIFE est que vous pouvez également définir des choses à l'intérieur et exposer uniquement les parties que vous souhaitez au monde extérieur (un exemple d'espacement de noms afin que vous puissiez essentiellement créer votre propre bibliothèque / plugin):
Vous pouvez maintenant appeler
myPlugin.public_function1()
, mais vous ne pouvez pas y accéderprivate_function()
! Tellement similaire à une définition de classe. Pour mieux comprendre cela, je recommande les liens suivants pour quelques lectures supplémentaires:ÉDITER
J'ai oublié de mentionner. Dans cette finale
()
, vous pouvez passer tout ce que vous voulez à l'intérieur. Par exemple, lorsque vous créez des plugins jQuery, vous passezjQuery
ou$
aimez:Donc, ce que vous faites ici est de définir une fonction qui accepte un paramètre (appelé
jQ
, une variable locale, et connu uniquement de cette fonction). Ensuite, vous invoquez automatiquement la fonction et passez un paramètre (également appeléjQuery
, mais celui- ci provient du monde extérieur et fait référence à la jQuery proprement dite ). Il n'y a aucun besoin urgent de le faire, mais il y a certains avantages:Plus tôt, j'ai décrit comment ces fonctions s'exécutent automatiquement au démarrage, mais si elles s'exécutent automatiquement, qui passe les arguments? Cette technique suppose que tous les paramètres dont vous avez besoin sont déjà définis en tant que variables globales. Donc, si jQuery n'était pas déjà défini comme une variable globale, cet exemple ne fonctionnerait pas. Comme vous pouvez le deviner, une des choses que jquery.js fait lors de son initialisation est de définir une variable globale 'jQuery', ainsi que sa plus célèbre variable globale '$', qui permet à ce code de fonctionner après que jQuery ait été inclus.
la source
;(function(jQ) { ... code ... })(jQuery);
cette façon, si quelqu'un laissait un point-virgule dans son script, il ne casserait pas le vôtre, surtout si vous envisagez de minimiser et de concaténer votre script avec d'autres.(function (context) { ..... })(this)
ce qui vous permet ensuite d'attacher tout ce que vous aimez au contexte parent, l'exposant ainsi.En bref
Sommaire
Dans sa forme la plus simple, cette technique vise à envelopper le code dans une portée de fonction .
Il aide à diminuer les chances de:
Il ne détecte lorsque le document est prêt - il est une sorte de
document.onload
niwindow.onload
Il est communément appelé
Immediately Invoked Function Expression (IIFE)
ouSelf Executing Anonymous Function
.Code expliqué
Dans l'exemple ci-dessus, toute variable définie dans la fonction (c'est-à-dire déclarée à l'aide
var
) sera "privée" et accessible UNIQUEMENT dans le cadre de la fonction (comme le dit Vivin Paliath). En d'autres termes, ces variables ne sont pas visibles / accessibles en dehors de la fonction. Voir la démo en direct .Javascript a une portée de fonction. "Les paramètres et variables définis dans une fonction ne sont pas visibles en dehors de la fonction, et qu'une variable définie n'importe où dans une fonction est visible partout dans la fonction." (extrait de "Javascript: The Good Parts").
Plus de détails
Code alternatif
En fin de compte, le code affiché avant pourrait également être fait comme suit:
Voir la démo en direct .
Les racines
Itération 1
Un jour, quelqu'un a probablement pensé "qu'il doit y avoir un moyen d'éviter de nommer" myMainFunction ", car tout ce que nous voulons, c'est l'exécuter immédiatement."
Si vous revenez à l'essentiel, vous découvrez que:
expression
: quelque chose évaluant à une valeur. c'est à dire3+11/x
statement
: ligne (s) de code faisant quelque chose MAIS il n'évalue pas une valeur. c'est à direif(){}
De même, les expressions de fonction évaluent à une valeur. Et une conséquence (je suppose?) Est qu'ils peuvent être immédiatement invoqués:
Donc, notre exemple plus complexe devient:
Voir la démo en direct .
Itération 2
La prochaine étape est la pensée "pourquoi avoir
var myMainFunction =
si nous ne l'utilisons même pas!?".La réponse est simple: essayez de supprimer cela, comme ci-dessous:
Voir la démo en direct .
Cela ne fonctionnera pas car "les déclarations de fonctions ne sont pas invocables" .
L'astuce est qu'en supprimant,
var myMainFunction =
nous avons transformé l' expression de fonction en une déclaration de fonction . Voir les liens dans "Ressources" pour plus de détails à ce sujet.La question suivante est «pourquoi ne puis-je pas la conserver comme expression de fonction avec autre chose que
var myMainFunction =
?La réponse est "vous pouvez", et il y a en fait plusieurs façons de le faire: ajouter un
+
, un!
, un-
, ou peut-être encapsuler une paire de parenthèses (comme c'est maintenant fait par convention), et plus je crois. Comme exemple:ou
ou
Donc, une fois que la modification pertinente est ajoutée à ce qui était autrefois notre "Code alternatif", nous revenons au même code exact que celui utilisé dans l'exemple "Code expliqué"
En savoir plus sur
Expressions vs Statements
:Démystifier les portées
Une chose que l'on pourrait se demander est "ce qui se passe lorsque vous ne définissez PAS la variable" correctement "à l'intérieur de la fonction - c'est-à-dire que vous effectuez une simple affectation à la place?"
Voir la démo en direct .
Fondamentalement, si une variable qui n'a pas été déclarée dans sa portée actuelle se voit attribuer une valeur, alors "une recherche dans la chaîne de portée se produit jusqu'à ce qu'elle trouve la variable ou atteigne la portée globale (à quel moment elle la créera)".
Dans un environnement de navigateur (par rapport à un environnement de serveur comme nodejs), la portée globale est définie par l'
window
objet. Par conséquent, nous pouvons le fairewindow.myOtherFunction()
.Mon conseil "Bonnes pratiques" sur ce sujet est de toujours l'utiliser
var
lors de la définition de quelque chose : que ce soit un nombre, un objet ou une fonction, et même lorsqu'il est dans la portée globale. Cela rend le code beaucoup plus simple.Remarque:
block scope
(Mise à jour: l' étendue de bloc variables locales ajoutées dans ES6 .)function scope
&global scope
(window
portée dans un environnement de navigateur)En savoir plus sur
Javascript Scopes
:Ressources
Prochaines étapes
Une fois que vous obtenez ce
IIFE
concept, il mène aumodule pattern
, ce qui est généralement fait en tirant parti de ce modèle IIFE. S'amuser :)la source
Javascript dans un navigateur n'a vraiment que deux étendues efficaces: l'étendue des fonctions et l'étendue globale.
Si une variable n'est pas dans l'étendue d'une fonction, elle est dans l'étendue globale. Et les variables globales sont généralement mauvaises, c'est donc une construction pour garder les variables d'une bibliothèque pour elle-même.
la source
Cela s'appelle une fermeture. Il scelle essentiellement le code à l'intérieur de la fonction afin que les autres bibliothèques n'interfèrent pas avec elle. C'est similaire à la création d'un espace de noms dans les langues compilées.
Exemple. Supposons que j'écris:
Désormais, les autres bibliothèques ne peuvent pas accéder à la variable que
x
j'ai créée pour l'utiliser dans ma bibliothèque.la source
(function(){ ... return { publicProp1: 'blah' }; })();
. Évidemment, pas parfaitement parallèle à l'espace de noms, mais cela peut aider à penser de cette façon.Vous pouvez également utiliser des fermetures de fonctions en tant que données dans des expressions plus grandes, comme dans cette méthode de détermination de la prise en charge du navigateur pour certains des objets html5.
la source
En plus de garder les variables locales, une utilisation très pratique consiste à écrire une bibliothèque à l'aide d'une variable globale, vous pouvez lui donner un nom de variable plus court à utiliser dans la bibliothèque. Il est souvent utilisé pour écrire des plugins jQuery, car jQuery vous permet de désactiver la variable $ pointant vers jQuery, en utilisant jQuery.noConflict (). Dans le cas où il est désactivé, votre code peut toujours utiliser $ et ne pas se casser si vous le faites simplement:
la source
la source
Nous devons également utiliser 'use strict' dans la fonction scope pour nous assurer que le code doit être exécuté en "mode strict". Exemple de code illustré ci-dessous
la source