57 votes

Fonction Init en javascript et comment elle fonctionne

Je vois souvent le code suivant :

(function () {
  // init part
})();

mais je n'ai jamais pu comprendre comment ça marche. Je trouve les dernières parenthèses particulièrement déroutantes. Quelqu'un pourrait-il m'expliquer comment cela fonctionne en termes de contextes d'exécution (EC) et d'objets variables (VO) ?

2 votes

Êtes-vous intéressé par une "explication formelle", en termes de spécification ECMA-262 ?

1 votes

Lisez à propos de la objectif de cette construction . Jetez un coup d'œil à une explication également aquí . Pour la syntaxe, voir pourquoi les parenthèses sont nécessaires y où ils devraient aller .

81voto

Andrew Points 5374

La façon dont j'explique généralement cela aux gens est de montrer comment il est similaire à d'autres modèles JavaScript.

Tout d'abord, vous devez savoir qu'il existe deux façons de déclarer une fonction (en fait, il y en a au moins cinq, mais ce sont les deux principales) :

function foo() {/*code*/}

y

var foo = function() {/*code*/};

Même si cette construction semble étrange, vous l'utilisez probablement tout le temps lorsque vous attachez des événements :

window.onload=function(){/*code*/};

Vous remarquerez que la deuxième forme n'est pas très différente d'une déclaration de variable ordinaire :

var bar = 5;
var baz = 'some string';
var foo = function() {/*code*/};

Mais en JavaScript, vous avez toujours le choix entre utiliser une valeur directement ou par le biais d'une variable. Si bar es 5 alors les deux affirmations suivantes sont équivalentes :

var myVal = bar * 100; // use 'bar'
var myVal = 5 * 100;   // don't use 'bar'

Eh bien, si vous pouvez utiliser 5 seul, pourquoi ne pouvez-vous pas utiliser function() {\*code*\} tout seul aussi ? En fait, c'est possible. Et cela s'appelle une fonction anonyme. Ces deux exemples sont donc également équivalents :

var foo = function() {/*code*/}; // use 'foo'
foo();                           

(function(){/*code*/})();        // don't use 'foo' 

La seule différence que vous devriez voir est dans les crochets supplémentaires. C'est simplement parce que si vous commencez une ligne avec le mot-clé function le parseur pensera que vous déclarez une fonction en utilisant le tout premier modèle en haut de cette réponse et lancera une exception pour erreur de syntaxe. Enveloppez donc votre fonction anonyme entière dans une paire d'accolades et le problème disparaît.

En d'autres termes, les trois affirmations suivantes sont valables :

5;                        // pointless and stupid
'some string';            // pointless and stupid
(function(){/*code*/})(); // wonderfully powerful

[EDIT en 2020]

La version précédente de ma réponse recommandait la forme de parens-wrapping de Douglas Crockford pour ces "fonctions anonymes immédiatement invoquées". L'utilisateur @RayLoveless a recommandé en 2012 d'utiliser la version présentée maintenant. À l'époque, avant ES6 et les fonctions fléchées, il n'y avait pas de différence idiomatique évidente ; il fallait simplement empêcher que la déclaration commençant par le signe function mot-clé. En fait, il y avait de nombreuses façons de le faire. Mais en utilisant les parens, ces deux déclarations étaient syntaxiquement et idiomatiquement équivalentes :

( function() { /* code */}() );
( function() { /* code */} )();

Mais le commentaire de l'utilisateur @zentechinc ci-dessous me rappelle que les fonctions fléchées changent tout cela. Donc maintenant, une seule de ces déclarations est correcte.

( () => { /* code */ }() ); // Syntax error
( () => { /* code */ } )();

Pourquoi diable cela est-il important ? En fait, c'est assez facile à démontrer. Rappelez-vous qu'une fonction flèche peut se présenter sous deux formes de base :

() => { return 5; };       // With a function body
() => { console.log(5); };

() => 5;                   // Or with a single expression
() => console.log(5);

Si des parens n'entourent pas ce deuxième type de fonction flèche, on se retrouve avec un désordre idiomatique :

() => 5();              // How do you invoke a 5?
() => console.log(5)(); // console.log does not return a function!

2 votes

"La façon dont je l'explique habituellement aux gens est de montrer comment il est similaire à d'autres modèles JavaScript." C'était incroyablement utile, donc merci de prendre votre temps et de faire ça :).

1 votes

Je pense que tu as tapé (function(){/*code*/}()) ; tu voulais taper (function(){/*code*/})() ;. C'est bien cela ?

0 votes

Non, mais ça n'a pas d'importance. Douglas Crockford recommande la forme que j'ai utilisée, alors que beaucoup de gens recommandent la vôtre. Voir stackoverflow.com/questions/3783007/ . Il se trouve que la raison des parenthèses est que vous essayez d'éviter de commencer l'instruction par function (vous pourriez donc tout aussi bien faire !function(){/*code*/}() o -function(){/*code*/}() . Je n'aime pas tout ce que Crockford recommande, mais je pense que sa cohérence rigoureuse est meilleure que l'alternative du "chacun fait ce qu'il veut", et son outil de linting (JSLint) l'exige.

51voto

ken Points 1925

Ce modèle créera un nouveau contexte d'exécution (CE) dans lequel tous les objets variables locaux (VO) vivront, et mourront également lorsque le CE sortira. La seule exception à cette durée de vie est pour les VO qui font partie d'un contexte d'exécution fermeture .

Veuillez noter que JavaScript n'a pas de fonction magique "init". Vous pouvez associer ce modèle à cette fonction puisque toute bibliothèque JS qui se respecte (jQuery, YUI, etc.) le fait pour ne pas polluer le NS global plus que nécessaire.

Une démonstration :

var x = 1; // global VO
(function(){        
    var x = 2; // local VO
})();
x == 1; // global VO, unchanged by the local VO

Le deuxième ensemble de "parenthèses" (il s'agit en fait de parens, ou d'un ensemble de parenthèses) sert simplement à invoquer l'expression de la fonction qui le précède directement (telle que définie par l'ensemble de parenthèses précédent).

7 votes

Si vous aviez expliqué ce qu'étaient une CE et une VO pour les développeurs qui ne comprennent pas, je vous aurais donné un vote positif, mais au lieu d'une réponse complète, c'est une réponse pour laquelle je vais devoir chercher des acronymes sur Google.

14 votes

Je n'ai pas défini EC et VO parce que la question originale contenait des définitions pour ceux-ci, donc si vous lisez la question, vous devriez déjà savoir ce qu'ils signifient ;) Aussi, ces 2 pages pourraient vous aider à mieux comprendre les EC/VO (variables) : 1. jibbering.com/faq 2. jibbering.com/faq/notes/clôtures

26voto

Guffa Points 308133

Le code crée une fonction anonyme, puis l'exécute immédiatement. Similaire à :

var temp = function() {
  // init part
}
temp();

Le but de cette construction est de créer une portée pour le code à l'intérieur de la fonction. Vous pouvez déclarer des variables et des fonctions à l'intérieur de la portée, et celles-ci seront locales à cette portée. De cette façon, ils n'encombrent pas la portée globale, ce qui minimise le risque de conflits avec d'autres scripts.

0 votes

Respectueusement, pour ceux d'entre vous qui continuent à voter cette réponse, la solution donnée ne répond à aucune des questions posées par le PO. du tout . Il pose des questions sur la dernière série de parenthèses [sic] et sur la manière dont le code donné est lié aux CE et aux VO... La réponse fournie par Guffa ressemble à la réponse habituelle d'une fonction anonyme qui n'aborde pas les points spécifiques soulevés par le PO.

3 votes

@ken : Les gens semblent apprécier la façon dont j'explique ce que fait le code, et pourquoi il est utilisé. Ce n'est pas parce que je n'utilise pas les mêmes termes que toi que c'est faux.

0 votes

Je n'ai jamais dit que c'était /wrong/, je faisais juste remarquer que ta réponse copier/coller ne prend pas en compte ce que le PO a demandé, c'est tout.

14voto

SEoF Points 324

Je n'arrive pas à croire que personne n'ait répondu à la question sur les opérations !

La dernière série de parenthèses est utilisée pour transmettre les paramètres à la fonction anonyme. Ainsi, l'exemple suivant crée une fonction, puis l'exécute avec les paramètres x=5 et y=8

(function(x,y){
    //code here
})(5,8)

Cela peut sembler peu utile, mais cela a sa place. Le plus courant que j'ai vu est

(function($){
    //code here
})(jQuery)

qui permet à jQuery d'être en mode compatible, mais vous pouvez y faire référence en tant que "$" dans la fonction anonyme.

1 votes

Cela peut également améliorer les performances en raccourcissant le chaîne de mesure pour cette variable particulière.

7voto

Alvaro Points 51

Fonction anonyme auto-invoquante (SIAF)

Les fonctions d'auto-invocation fonctionnent instantanément, même si DOM n'est pas complètement prêt.

jQuery document.ready vs auto appel de fonction anonyme

0 votes

Merci de partager le nom avec ce fil de discussion...très utile

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