Comprendre les IIFE

J'ai beaucoup de difficulté à comprendre "Expression de fonction invoquée immédiatement" (IIFE's).

J'essaye de concevoir un jeu (j'ai un modèle de travail en ce moment, mais ce n'est pas orienté objet et mon but est de mieux concevoir et implémenter du code), et on m'a dit de ne pas rendre mes références globales.

Voici ce que j'ai en ce moment.

var engine = new _engine();
engine.count++; //there's a lot more to the engine, I just haven't converted it yet

Voici ce que j'ai essayé:

(function() { var engine = new _engine(); }());
engine.count++; //error, engine is not defined

Alors maintenant j'essaie ça, et ça marche, mais j'ai peur que ça soit encore global!

var engine = (function(){ return new _engine(); }());
engine.count++; //works, but is this still global?

La conception d'objets en JavaScript est un concept très nouveau pour moi, donc je veux être absolument sûr que j'apprends la bonne façon de le faire, et comprendre pourquoi cela fonctionne.

S'il vous plaît noter que je dois être en mesure d'accéder au moteur de n'importe où dans la page. Est-ce que cela rend le besoin d'un global? Pourquoi les globals sont-ils si désapprouvés? (D'autres objets référencent le moteur en fonction des retours de fonction et des variables booléennes)

0
IIFE n'a rien à voir avec la programmation orientée objet. Les gens l'utilisent surtout parce que JavaScript n'a pas de système de paquets ou de modules, ils ont donc besoin d'invoquer une fonction pour ne pas créer un tas de variables globales. En outre, ils s'habituent à émuler la portée du bloc. De votre simple exemple, je dirais qu'il n'y a aucune raison d'en utiliser un.
ajouté l'auteur Blue Skies, source

2 Réponses

Voici un exemple de conception acceptable pour ce que vous essayez d'accomplir. À la fin de votre application aura un seul point d'entrée et utilisera une seule variable globale qui est utilisée comme espace de noms de votre application.

Vous pouvez et devez probablement utiliser l'injection de dépendance au moment de la construction (ou en utilisant un injecteur) pour injecter des dépendances dans des objets plutôt que de vous fier à des variables externes bien connues.

Si vous êtes vraiment sérieux dans l'écriture de code modulaire, consultez RequireJS .

Engine.js

(function (ns) {
    function Engine() {
    }

    Engine.prototype.someMethod = function() {
    };

    ns.Engine = Engine;
})(window.myNamespace = window.myNamespace || {});

Game.js

(function (ns) {
    function Game(engine) {
        this._engine = engine;
    }

    Game.prototype.start = function() {
        this._engine.someMethod();
    };

    ns.Game = Game;
})(window.myNamespace = window.myNamespace || {});

app.js

//kickstart your app
(function() {
    var engine = new myNamespace.Engine(),

        //init the Game while injecting the engine dependency
        game = new myNamespace.Game(engine);

    game.start();
})();
1
ajouté

Je pense que vous cherchez ce qui suit:

(function() {
    var engine = new _engine();
    engine.count++;
   //all other code depending on engine should be in here as well
})();

Votre code fera exactement la même chose que votre version originale, mais maintenant engine est local à l'IIFE au lieu d'être global.

edit: After the discussion in comments, it sounds like you really do need engine to be global. In this case you are probably fine leaving your code the way it is, but to make sure you aren't exposing any other variables as globals besides engine you could do something like the following:

var engine = (function() {
   var engine = new _engine();
   engine.count++;
  //any other code from your engine file (probably the _engine definition, etc)

   return engine; //return local engine from the IIFE
})();

Ou bien (c'est ce que jQuery et d'autres bibliothèques populaires utilisent):

(function(window) {
   var engine = new _engine();
   engine.count++;
  //any other code from your engine file (probably the _engine definition, etc)

   window.engine = engine; //assign engine to window.engine to make it global
})(window);
1
ajouté
Mais si j'ai besoin d'exécuter différentes fonctions et variables de moteur dans différents endroits, comment puis-je faire cela? Je veux seulement utiliser new _engine() une fois, et pouvoir le référencer là où j'en ai besoin.
ajouté l'auteur Sterling Archer, source
Est-ce que ce serait un bon design? On m'a dit que les globals sont une mauvaise pratique
ajouté l'auteur Sterling Archer, source
Je ne pense pas que ce soit possible, d'autres objets devront pointer vers l'objet moteur et je ne peux pas tout mettre dans un IIFE que je suppose.
ajouté l'auteur Sterling Archer, source
Ahh, mais je vais avoir des fichiers séparés pour chaque objet D:
ajouté l'auteur Sterling Archer, source
@ F.J Polluer l'espace de noms global n'est jamais nécessaire. Vous pouvez réaliser ce que l'OP essaie de faire en utilisant des objets de nommage et en utilisant l'injection de dépendance.
ajouté l'auteur plalx, source
Vous pouvez aussi mettre tout ce code dans l'IIFE, ou simplement laisser votre code tel qu'il est dans votre premier bloc.
ajouté l'auteur Andrew Clark, source
Oui, il serait probablement préférable de tout mettre dans l'IIFE.
ajouté l'auteur Andrew Clark, source
En supposant que tout votre code se trouve dans un seul fichier, vous pouvez presque simplement ajouter (function() { avant tout votre code et }) (); après. Tout fonctionnera probablement de la même manière, sans pollution de l'espace de noms global.
ajouté l'auteur Andrew Clark, source