web-dev-qa-db-fra.com

Quel est le but d'une fonction à exécution automatique en javascript?

En javascript, quand voulez-vous utiliser ceci:

(function(){
    //Bunch of code...
})();

sur ceci:

//Bunch of code...
397
Ej.

Son tout sur la portée variable. Les variables déclarées dans la fonction à exécution automatique sont, par défaut, uniquement disponibles pour le code dans la fonction à exécution automatique. Cela permet d’écrire du code sans se soucier de la façon dont les variables sont nommées dans d’autres blocs de code javascript.

Par exemple:

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

alert(foo); 

Cela alertera d’abord "3" puis jettera une erreur à la prochaine alerte car foo n’est pas défini.

376
Ken Browning

Simpliste. Tellement normal, c'est presque réconfortant:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

Pourtant. Que se passe-t-il si j'inclus sur ma page une bibliothèque javascript vraiment pratique qui convertit les caractères avancés en représentations de base?

Attends quoi?

Je veux dire. Si quelqu'un tape un caractère avec un accent particulier (comme un caractère français ou espagnol) mais que je ne veux que des caractères "anglais"? A-z dans mon programme? Eh bien ... Les caractères espagnols 'n ~' et français 'e /' (j'ai utilisé deux caractères chacun pour ceux-ci, mais vous pouvez probablement faire le saut mental dans le caractère qui représente les accents), ces caractères peuvent être traduits en caractères de base de 'n' et 'e'.

Donc, quelqu'un de gentil a écrit un convertisseur de personnage complet que je peux inclure dans mon site ... je l'inclue.

Un problème: il a une fonction appelée "nom" identique à ma fonction.

C'est ce qu'on appelle une collision. Nous avons deux fonctions déclarées dans le même scope avec le même nom. Nous voulons éviter cela.

Nous devons donc définir notre code d'une manière ou d'une autre.

La seule manière de coder le code en javascript est de l'envelopper dans une fonction:

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Cela pourrait résoudre notre problème. Tout est maintenant fermé et accessible uniquement à partir de nos accolades d’ouverture et de fermeture.

Nous avons une fonction dans une fonction ... qui est bizarre à regarder, mais totalement légale.

Un seul problème. Notre code ne fonctionne pas. Notre variable userName n'est jamais répercutée dans la console!

Nous pouvons résoudre ce problème en ajoutant un appel à notre fonction après notre bloc de code existant ...

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

main();

Ou avant!

main();

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Une préoccupation secondaire: quelles sont les chances que le nom "principal" n'ait pas encore été utilisé? ... tellement, très mince.

Nous avons besoin de PLUS de portée. Et un moyen d'exécuter automatiquement notre fonction main ().

Nous arrivons maintenant aux fonctions d’exécution automatique (ou d’exécution automatique, d’exécution automatique, peu importe).

(() {}) ();

La syntaxe est maladroite comme péché. Cependant, cela fonctionne.

Lorsque vous mettez une définition de fonction entre parenthèses et que vous incluez une liste de paramètres (un autre ensemble ou des parenthèses!), Elle agit comme une fonction appel.

Voyons donc à nouveau notre code, avec une syntaxe auto-exécutable:

(function main() {
  var userName = "Sean";

    console.log(name());

    function name() {
      return userName;
    }
  }
)();

Donc, dans la plupart des tutoriels que vous lisez, vous allez maintenant être bombardés du terme 'exécution automatique anonyme' ou quelque chose de similaire.

Après de nombreuses années de développement professionnel, je fortement vous invite à nommer chaque fonction que vous écrivez à des fins de débogage.

En cas de problème (et ce sera le cas), vous vérifierez la trace dans votre navigateur. Il est toujours plus facile de limiter vos problèmes de code lorsque les entrées de la trace de la pile ont des noms!

Très long et j'espère que ça aide!

79
Sean Holden

L'auto-invocation (également appelée auto-invocation) se produit lorsqu'une fonction s'exécute immédiatement après sa définition. Il s'agit d'un modèle de base qui sert de base à de nombreux autres modèles de développement JavaScript.

Je suis un grand fan :) parce que:

  • Il garde le code au minimum
  • Il impose la séparation du comportement de la présentation
  • Il fournit une fermeture qui empêche les conflits de noms

Énormément Pourquoi devriez-vous dire que c'est bon?)

Plus --- (ici .

33
M A Hossain Tonu

Noms de noms. Les champs d'application de JavaScript sont au niveau de la fonction.

19
Christoph

Je ne peux pas croire qu'aucune des réponses ne mentionne les globales implicites.

La construction (function(){})() ne protège pas contre les globales implicites, ce qui est pour moi une préoccupation majeure, voir http://yuiblog.com/blog/2006/06/01/global-domination/

Fondamentalement, le bloc de fonction s'assure que tous les "vars globaux" dépendants que vous avez définis sont confinés à votre programme, il ne vous protège pas contre la définition de globaux implicites. JSHint ou similaire peut fournir des recommandations sur la manière de se défendre contre ce comportement.

La syntaxe plus concise de var App = {} fournit un niveau de protection similaire et peut être encapsulée dans le bloc de fonction si elle se trouve sur des pages "publiques". (voir Ember.js ou SproutCore pour des exemples concrets de bibliothèques utilisant cette construction)

En ce qui concerne les propriétés private, elles sont en quelque sorte surestimées sauf si vous créez un framework public ou une bibliothèque, mais si vous devez les mettre en œuvre, Douglas Crockford a de bonnes idées.

12
David W. Keith

Existe-t-il un paramètre et le "groupe de codes" renvoie une fonction?

var a = function(x) { return function() { document.write(x); } }(something);

Fermeture. La valeur de something est utilisée par la fonction affectée à a. something pourrait avoir une valeur variable (pour la boucle) et chaque fois que a a une nouvelle fonction.

7
stesch

Isolement de la portée, peut-être. Pour que les variables à l'intérieur de la déclaration de fonction ne polluent pas l'espace de noms externe.

Bien sûr, sur la moitié des implémentations JS, elles le seront quand même.

6
chaos

J'ai lu toutes les réponses, il manque quelque chose de très important ici, je vais baiser. Il y a deux raisons principales pour lesquelles j'ai besoin de fonctions anonymes à auto-exécution, ou mieux "Expression de fonction immédiatement appelée (IIFE)":

  1. Meilleure gestion des espaces de noms (éviter la pollution des espaces de noms -> module JS)
  2. Fermetures (simuler des membres de la classe privée, comme indiqué dans la POO)

Le premier a été très bien expliqué. Pour le second, veuillez étudier l'exemple suivant:

var MyClosureObject = (function (){
  var MyName = 'Michael Jackson RIP';
  return {
    getMyName: function () { return MyName;},
    setMyName: function (name) { MyName = name}
  }
}());

Attention 1: Nous n'affectons pas de fonction à MyClosureObject, ni plus le résultat de l'invocation de cette fonction. Soyez conscient de () à la dernière ligne.

Attention 2: De plus, que devez-vous savoir sur les fonctions en Javascript, c'est que les fonctions internes obtiennent accès aux paramètres et variables des fonctions, elles sont définies à l'intérieur.

Essayons quelques expériences:

Je peux obtenir MyName en utilisant getMyName et cela fonctionne:

 console.log(MyClosureObject.getMyName()); 
 // Michael Jackson RIP

L'approche ingénieuse suivante ne fonctionnerait pas:

console.log(MyClosureObject.MyName); 
// undefined

Mais je peux définir un autre nom et obtenir le résultat attendu:

MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName()); 
// George Michael RIP

Edit: Dans l'exemple ci-dessus, MyClosureObject est conçu pour être utilisé sans le préfixe new, par conséquent, il ne doit pas être capitalisé.

6
Lonely

Voici un exemple concret de l’utilité d’une fonction anonyme invocante.

for( var i = 0; i < 10; i++ ) {
  setTimeout(function(){
    console.log(i)
  })
}

Sortie: 10, 10, 10, 10, 10...

for( var i = 0; i < 10; i++ ) {
  (function(num){
    setTimeout(function(){
      console.log(num)
    })
  })(i)
}

Sortie: 0, 1, 2, 3, 4...

5
sg.cc

Une différence est que les variables que vous déclarez dans la fonction sont locales, elles disparaissent donc lorsque vous quittez la fonction et n'entrent pas en conflit avec d'autres variables dans un autre code.

3
Guffa

Fonction invoquée en javascript:

Une expression auto-invoquante est invoquée (démarrée) automatiquement, sans être appelée. Une expression auto-invoquante est invoquée juste après sa création. Ceci est essentiellement utilisé pour éviter les conflits de noms ainsi que pour réaliser l'encapsulation. Les variables ou les objets déclarés ne sont pas accessibles en dehors de cette fonction. Pour éviter les problèmes de minimisation (filename.min), utilisez toujours la fonction auto-exécutée.

2
Kishor Vitekar

Puisque les fonctions en Javascript sont des objets de première classe, en les définissant ainsi, une "classe" ressemble beaucoup à C++ ou C #.

Cette fonction peut définir des variables locales et contenir des fonctions. Les fonctions internes (effectivement les méthodes d'instance) auront accès aux variables locales (effectivement les variables d'instance), mais elles seront isolées du reste du script.

1
James Curran

Les fonctions d’exécution automatique permettent de gérer la portée d’une variable.

La portée d'une variable est la région de votre programme dans laquelle elle est définie.

Une variable globale a une portée globale; il est défini partout dans votre code JavaScript et est accessible de n'importe où dans le script, même dans vos fonctions. D'autre part, les variables déclarées dans une fonction ne sont définies que dans le corps de la fonction. Ce sont des variables locales, ont une portée locale et ne sont accessibles que dans cette fonction. Les paramètres de fonction comptent également en tant que variables locales et sont définis uniquement dans le corps de la fonction.

Comme indiqué ci-dessous, vous pouvez accéder à la variable variable globale dans votre fonction et noter que, dans le corps d'une fonction, une variable locale est prioritaire sur une variable globale du même nom.

var globalvar = "globalvar"; // this var can be accessed anywhere within the script

function scope() {
    alert(globalvar);
    localvar = "localvar" //can only be accessed within the function scope
}

scope(); 

En gros, une fonction à exécution automatique permet d’écrire du code sans se soucier de la façon dont les variables sont nommées dans d’autres blocs de code javascript.

1
(function(){
    var foo = {
        name: 'bob'
    };
    console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

En fait, la fonction ci-dessus sera traitée comme une expression de fonction sans nom.

Le principal objectif de l'encapsulation d'une fonction avec des parenthèses fermées et ouvertes est d'éviter de polluer l'espace global.

Les variables et les fonctions à l'intérieur de l'expression de fonction sont devenues privées (c'est-à-dire), elles ne seront plus disponibles en dehors de la fonction.

0
Madhankumar

On dirait que cette question a été résolue, mais je posterai quand même mes commentaires.

Je sais quand j'aime utiliser des fonctions auto-exécutables.

var myObject = {
    childObject: new function(){
        // bunch of code
    },
    objVar1: <value>,
    objVar2: <value>
}

La fonction me permet d’utiliser un code supplémentaire pour définir les attributs et les propriétés de childObjects pour un code plus propre, tels que la définition de variables couramment utilisées ou l’exécution d’équations mathématiques; Oh! ou vérification d'erreur. par opposition à être limité à la syntaxe d'instanciation d'objet imbriquée de ...

object: {
    childObject: {
        childObject: {<value>, <value>, <value>}
    }, 
    objVar1: <value>,
    objVar2: <value>
}

Le codage en général a beaucoup de façons obscures de faire beaucoup de choses identiques, ce qui vous amène à vous demander: "Pourquoi se donner la peine?" Mais de nouvelles situations apparaissent sans cesse et vous ne pouvez plus vous fier uniquement aux principes de base/fondamentaux.

0
Garrett