web-dev-qa-db-fra.com

Pourquoi avez-vous besoin d'appeler une fonction anonyme sur la même ligne?

Je lisais quelques articles sur les bouclages et je l'ai vu partout, mais il n'y a pas d'explication claire sur la façon dont cela fonctionne - à chaque fois qu'on m'a juste dit de l'utiliser ...:

// Create a new anonymous function, to use as a wrapper
(function(){
    // The variable that would, normally, be global
    var msg = "Thanks for visiting!";

    // Binding a new function to a global object
    window.onunload = function(){
        // Which uses the 'hidden' variable
        alert( msg );
    };
// Close off the anonymous function and execute it
})();

Ok, je vois que nous allons créer une nouvelle fonction anonyme, puis l'exécuter. Donc après cela, ce code simple devrait fonctionner (et ça marche):

(function (msg){alert(msg)})('SO');

Ma question est quel genre de magie se passe ici? Je pensais que quand j'ai écrit:

(function (msg){alert(msg)})

alors une nouvelle fonction sans nom serait créée comme la fonction "" (msg) ...

mais alors pourquoi ça ne marche pas?

(function (msg){alert(msg)});
('SO');

Pourquoi doit-il être dans la même ligne?

Pourriez-vous s'il vous plaît me signaler quelques messages ou me donner une explication?

370
palig

Supprimez le point-virgule après la définition de la fonction.

(function (msg){alert(msg)})
('SO');

Ci-dessus devrait fonctionner.

DEMO Page: https://jsfiddle.net/e7ooeq6m/

J'ai discuté de ce type de modèle dans ce post:

jQuery et $ questions

EDIT:

Si vous regardez spécification de script ECMA , il existe 3 façons de définir une fonction. (Page 98, Section 13 Définition de la fonction)

1. Utiliser le constructeur de fonction

var sum = new Function('a','b', 'return a + b;');
alert(sum(10, 20)); //alerts 30

2. Utilisation de la déclaration de fonction.

function sum(a, b)
{
    return a + b;
}

alert(sum(10, 10)); //Alerts 20;

3. Expression de fonction

var sum = function(a, b) { return a + b; }

alert(sum(5, 5)); // alerts 10

Vous pouvez donc vous demander quelle est la différence entre déclaration et expression?

De la spécification ECMA Script:

FunctionDeclaration: Identifiant de la fonction (FormalParameterListopt) {FunctionBody}

FunctionExpression: function Identifieropt (FormalParameterListopt) {FunctionBody}

Si vous remarquez, 'identifiant' est facultatif pour l'expression de la fonction. Et lorsque vous ne donnez pas d'identifiant, vous créez une fonction anonyme. Cela ne signifie pas que vous ne pouvez pas spécifier d'identifiant.

Cela signifie que le suivi est valide.

var sum = function mySum(a, b) { return a + b; }

Le point important à noter est que vous ne pouvez utiliser "mySum" qu’à l’intérieur du corps de la fonction mySum, pas à l’extérieur. Voir l'exemple suivant:

var test1 = function test2() { alert(typeof test2); }

alert(typeof(test2)); //alerts 'undefined', surprise! 

test1(); //alerts 'function' because test2 is a function.

Démo en direct

Comparez ceci à

 function test1() { alert(typeof test1) };

 alert(typeof test1); //alerts 'function'

 test1(); //alerts 'function'

Forts de ces connaissances, essayons d’analyser votre code.

Quand vous avez un code comme,

    function(msg) { alert(msg); }

Vous avez créé une expression de fonction. Et vous pouvez exécuter cette expression de fonction en l'enveloppant entre parenthèses.

    (function(msg) { alert(msg); })('SO'); //alerts SO.
376
SolutionYogi

C'est ce qu'on appelle une fonction auto-invoquée.

Ce que vous faites lorsque vous appelez (function(){}) renvoie un objet fonction. Lorsque vous y ajoutez (), il est appelé et tout élément du corps est exécuté. Le ; indique la fin de l'instruction, c'est pourquoi la 2ème invocation échoue.

127
seth

Une chose que j'ai trouvée déroutante est que les "()" regroupent des opérateurs.

Voici votre fonction déclarée de base.

Ex. 1:

var message = 'SO';

function foo(msg) {
    alert(msg);
}

foo(message);

Les fonctions sont des objets et peuvent être regroupées. Alors jetons des parens autour de la fonction.

Ex. 2:

var message = 'SO';

function foo(msg) {  //declares foo
    alert(msg);
}

(foo)(message);     // calls foo

Maintenant, au lieu de déclarer et d'appeler immédiatement la même fonction, nous pouvons utiliser la substitution de base pour la déclarer comme nous l'appelons.

Ex. 3.

var message = 'SO';

(function foo(msg) {
    alert(msg);
})(message);          // declares & calls foo

Enfin, nous n'avons pas besoin de ce foo supplémentaire car nous n'utilisons pas le nom pour l'appeler! Les fonctions peuvent être anonymes.

Ex. 4.

var message = 'SO';

(function (msg) {   // remove unnecessary reference to foo
    alert(msg);
})(message);

Pour répondre à votre question, reportez-vous à l'exemple 2. Votre première ligne déclare une fonction sans nom et la groupe, mais ne l'appelle pas. La deuxième ligne regroupe une chaîne. Les deux ne font rien. (Premier exemple de Vincent.)

(function (msg){alert(msg)});  
('SO');                       // nothing.

(foo); 
(msg); //Still nothing.

Mais

(foo)
(msg); //works
93
Benxamin

Une fonction anonyme n'est pas une fonction nommée "". C'est simplement une fonction sans nom.

Comme toute autre valeur en JavaScript, une fonction n'a pas besoin de nom pour être créée. Bien qu'il soit bien plus utile de le lier à un nom, comme toute autre valeur.

Mais comme toute autre valeur, vous souhaitez parfois l’utiliser sans la lier à un nom. C'est le motif invoquant soi-même.

Voici une fonction et un nombre, non liés, ils ne font rien et ne peuvent jamais être utilisés:

function(){ alert("plop"); }
2;

Nous devons donc les stocker dans une variable pour pouvoir les utiliser, comme toute autre valeur:

var f = function(){ alert("plop"); }
var n = 2;

Vous pouvez également utiliser le sucre syntaxique pour lier la fonction à une variable:

function f(){ alert("plop"); }
var n = 2;

Mais si les nommer n'est pas obligatoire et entraînerait plus de confusion et moins de lisibilité, vous pouvez simplement les utiliser tout de suite.

(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5

Ici, ma fonction et mes nombres ne sont pas liés à une variable, mais ils peuvent toujours être utilisés.

Dit comme ça, il semble que les fonctions auto-appelantes n’ont aucune valeur réelle. Mais vous devez garder à l'esprit que le délimiteur d'étendue JavaScript est la fonction et non le bloc ({}).

Ainsi, une fonction auto-invoquante a réellement la même signification qu'un bloc C++, C # ou Java. Ce qui signifie que la variable créée à l'intérieur ne "coulera" pas hors de la portée. Ceci est très utile en JavaScript pour ne pas polluer la portée globale.

23
Vincent Robert

C'est comme ça que JavaScript fonctionne. Vous pouvez déclarer une fonction nommée:

function foo(msg){
   alert(msg);
}

Et appelez ça:

foo("Hi!");

Ou, vous pouvez déclarer une fonction anonyme:

var foo = function (msg) {
    alert(msg);
}

Et appelez ça:

foo("Hi!");

Ou, vous pouvez simplement ne jamais lier la fonction à un nom:

(function(msg){
   alert(msg);
 })("Hi!");

Les fonctions peuvent également renvoyer des fonctions:

function make_foo() {
    return function(msg){ alert(msg) };
}

(make_foo())("Hi!");

Cela ne vaut rien que les variables définies avec "var" dans le corps de make_foo soient fermées par chaque fonction renvoyée par make_foo. Ceci est une fermeture, et cela signifie que toute modification apportée à la valeur par une fonction sera visible par une autre.

Cela vous permet d'encapsuler des informations, si vous le souhaitez:

function make_greeter(msg){
    return function() { alert(msg) };
}

var hello = make_greeter("Hello!");

hello();

C'est à peu près comme tous les langages de programmation, mais Java fonctionnent.

19
jrockway

Le code que vous affichez,

(function (msg){alert(msg)});
('SO');

se composent de deux déclarations. La première est une expression qui génère un objet fonction (qui sera ensuite récupéré car il n'est pas enregistré). La seconde est une expression qui donne une chaîne. Pour appliquer la fonction à la chaîne, vous devez soit passer la chaîne en tant qu’argument à la fonction lorsqu’elle est créée (que vous montrez également ci-dessus), soit vous devez stocker la fonction dans une variable, de manière à pouvoir appliquez-le plus tard, à votre guise. Ainsi:

var f = (function (msg){alert(msg)});
f('SO');

Notez qu'en stockant une fonction anonyme (une fonction lambda) dans une variable, vous lui donnez effectivement un nom. Par conséquent, vous pouvez également définir une fonction régulière:

function f(msg) {alert(msg)};
f('SO');
8
Stephan202

En résumé des commentaires précédents:

function() {
  alert("hello");
}();

lorsqu'il n'est pas affecté à une variable, génère une erreur de syntaxe. Le code est analysé comme une instruction de fonction (ou une définition), ce qui rend les parenthèses fermantes syntaxiquement incorrectes. L’ajout de parenthèses autour de la partie fonction indique à l’interprète (et au programmeur) qu’il s’agit d’une expression de fonction (ou invocation), comme dans

(function() {
  alert("hello");
})();

Il s’agit d’une fonction auto-invoquante, ce qui signifie qu’elle est créée anonymement et s’exécute immédiatement car l’invocation a lieu dans la même ligne où elle est déclarée. Cette fonction auto-invoquante est indiquée avec la syntaxe habituelle pour appeler une fonction sans argument, plus des parenthèses ajoutées autour du nom de la fonction: (myFunction)();.

Il y a ne bonne syntaxe de la fonction JavaScript SO discussion .

7
hotshot309

Cette réponse n’est pas strictement liée à la question, mais vous voudrez peut-être savoir que ce type de syntaxe n’est pas propre aux fonctions. Par exemple, nous pouvons toujours faire quelque chose comme ceci:

alert(
    {foo: "I am foo", bar: "I am bar"}.foo
); // alerts "I am foo"

Relatif aux fonctions. Comme ce sont des objets qui héritent de Function.prototype, on peut faire des choses comme:

Function.prototype.foo = function () {
    return function () {
        alert("foo");
    };
};

var bar = (function () {}).foo();

bar(); // alerts foo

Et vous savez, nous n'avons même pas à entourer les fonctions de parenthèses pour les exécuter. Quoi qu’il en soit, tant que nous essayons d’attribuer le résultat à une variable.

var x = function () {} (); // this function is executed but does nothing

function () {} (); // syntax error

Une autre chose que vous pouvez faire avec les fonctions, dès que vous les déclarez, est d'invoquer l'opérateur new et d'obtenir un objet. Les éléments suivants sont équivalents:

var obj = new function () {
    this.foo = "bar";
};

var obj = {
    foo : "bar"
};
3
Ionuț G. Stan

exemples sans crochets:

void function (msg) { alert(msg); }
('SO');

(c’est la seule utilisation réelle de void, afaik)

ou

var a = function (msg) { alert(msg); }
('SO');

ou

!function (msg) { alert(msg); }
('SO');

travailler aussi bien. la void provoque l'évaluation de l'expression, ainsi que l'affectation et le bang. le dernier fonctionne avec ~, +, -, delete, typeof, certains des opérateurs unaires (void sont également un ) ne fonctionnent pas sont de couse ++, -- en raison de la nécessité d’une variable.

le saut de ligne n'est pas nécessaire.

3
Nina Scholz

Ma compréhension de la question du demandeur est telle que:

Comment fonctionne cette magie:

(function(){}) ('input')   // Used in his example

J'ai peut-être tort. Cependant, la pratique habituelle que les gens connaissent est la suivante:

(function(){}('input') )

La raison en est telle que les parenthèses JavaScript AKA (), ne peuvent pas contenir d'instructions et lorsque l'analyseur rencontre le mot clé function, il sait comment l'analyser comme une expression de fonction et non comme une déclaration de fonction.

Source: article de blog expression de fonction immédiatement appelée (IIFE)

3
laycat

Il y a une autre propriété que JavaScript possède. Si vous voulez appeler la même fonction anonyme de manière récursive.

(function forInternalOnly(){

  //you can use forInternalOnly to call this anonymous function
  /// forInternalOnly can be used inside function only, like
  var result = forInternalOnly();
})();

//this will not work
forInternalOnly();// no such a method exist
3
Anoop

C'est une fonction anonyme à exécution automatique. Le premier ensemble de crochets contient les expressions à exécuter et le second ensemble exécute ces expressions.

(function () {
    return ( 10 + 20 );
})();

Peter Michaux discute de la différence entre ne paire de parenthèses importante .

C'est une construction utile lorsque vous essayez de masquer des variables de l'espace de noms parent. Tout le code de la fonction est contenu dans la portée privée de la fonction, ce qui signifie qu'il est impossible d'y accéder du tout en dehors de la fonction, ce qui le rend vraiment privé.

Voir:

  1. Fermeture (informatique)
  2. JavaScript Namespacing
  3. Paire importante de parenthèses Javascript
1
Ashwin Parmar
(function (msg){alert(msg)})
('SO');

Il s'agit d'une méthode courante d'utilisation d'une fonction anonyme en tant que fermeture utilisée par de nombreux frameworks JavaScript.

Cette fonction appelée est automatiquement lors de la compilation du code.

Si vous avez placé ; sur la première ligne, le compilateur l'a traitée comme deux lignes différentes. Donc, vous ne pouvez pas obtenir les mêmes résultats que ci-dessus.

Cela peut aussi être écrit comme:

(function (msg){alert(msg)}('SO'));

Pour plus de détails, regardez dans Fonctions JavaScript/Anonymes.

0
user2349539
  1. Les fonctions anonymes sont des fonctions déclarées dynamiquement lors de l'exécution. Elles sont appelées fonctions anonymes car elles ne reçoivent pas un nom de la même manière que les fonctions normales.

    Les fonctions anonymes sont déclarées à l'aide de l'opérateur de fonction au lieu de la déclaration de fonction. Vous pouvez utiliser l'opérateur de fonction pour créer une nouvelle fonction partout où il est valide de mettre une expression. Par exemple, vous pouvez déclarer une nouvelle fonction en tant que paramètre d'un appel de fonction ou affecter une propriété à un autre objet.

    Voici un exemple typique d’une fonction nommée:

    fonction flyToTheMoon () {alert ("Zoom! Zoom! Zoom!"); } Voler vers la lune(); Voici le même exemple créé en tant que fonction anonyme:

    var flyToTheMoon = function () {alert ("Zoom! Zoom! Zoom!"); } Voler vers la lune();

    Pour plus de détails, veuillez lire ici:

    http://helephant.com/2008/08/23/javascript-anonymous-functions/

0
Harikesh Yadav

L'IIFE compartimente simplement la fonction et cache la variable msg afin de ne pas "polluer" l'espace de nom global. En réalité, restez simple et faites comme ci-dessous, à moins que vous ne construisiez un site Web d'un milliard de dollars.

var msg = "later dude";
window.onunload = function(msg){
  alert( msg );
};

Vous pouvez nommer votre propriété msg en utilisant un modèle de module de révélation comme:

var myScript = (function() {
    var pub = {};
    //myscript.msg
    pub.msg = "later dude";
    window.onunload = function(msg) {
        alert(msg);
    };
    //API
    return pub;
}());
0
Ron Royston

Un autre point de vue

Tout d'abord, vous pouvez déclarer une fonction anonyme:

var foo = function(msg){
 alert(msg);
}

Ensuite, vous l'appelez:

foo ('Few');

Parce que foo = function (msg) {alert (msg);} vous pouvez donc remplacer foo par:

function(msg){
 alert(msg);
} ('Few');

Mais vous devez envelopper toute votre fonction anonyme dans une paire d'accolades pour éviter les erreurs de syntaxe lors de la déclaration de la fonction lors de l'analyse. Ensuite nous avons,

(function(msg){
 alert(msg);
}) ('Few');

De cette façon, c'est facile à comprendre pour moi.

0
capu

La raison simple pour laquelle cela ne fonctionne pas n'est pas due au ; indiquant la fin de la fonction anonyme. En effet, sans le () à la fin d'un appel de fonction, il ne s'agit pas d'un appel de fonction. C'est,

function help() {return true;}

Si vous appelez result = help();, il s'agit d'un appel à une fonction qui retournera la valeur true.

Si vous appelez result = help; ceci n'est pas un appel. Il s’agit d’une affectation dans laquelle l’aide est traitée comme des données à affecter au résultat.

Ce que vous avez fait a été de déclarer/instancier une fonction anonyme en ajoutant le point-virgule,

(function (msg) { /* Code here */ });

et ensuite essayé de l'appeler dans une autre déclaration en utilisant juste des parenthèses ... Évidemment parce que la fonction n'a pas de nom, mais cela ne fonctionnera pas:

('SO');

L'interprète voit les parenthèses sur la deuxième ligne comme une nouvelle instruction/instruction, et donc cela ne fonctionne pas, même si vous l'avez fait comme ceci:

(function (msg){/*code here*/});('SO');

Cela ne fonctionne toujours pas, mais cela fonctionne lorsque vous supprimez le point-virgule, car l'interprète ignore les espaces blancs et les chariots et considère le code complet comme une seule instruction.

(function (msg){/*code here*/})        // This space is ignored by the interpreter
('SO');

Conclusion: un appel de fonction n’est pas un appel de fonction sans le () à la fin, sauf dans des conditions spécifiques, telles que le fait d’être appelé par une autre fonction, c’est-à-dire que onload = 'help' exécuterait la fonction d’aide même si les parenthèses étaient non inclus. Je pense que setTimeout et setInterval autorisent également ce type d’appel de fonction et que l’interprète ajoute de toute façon les parenthèses dans les coulisses, ce qui nous ramène à "un appel de fonction n’est pas un appel de fonction sans parenthèses".

0
hired techniques

Quand vous avez fait:

(function (msg){alert(msg)});
('SO');

Vous avez terminé la fonction avant ('SO') à cause du point-virgule. Si vous écrivez juste:

(function (msg){alert(msg)})
('SO');

Ça va marcher.

Exemple de travail: http://jsfiddle.net/oliverni/dbVjg/

0
Oliver Ni