web-dev-qa-db-fra.com

Le moyen le plus simple/le plus propre d'implémenter singleton en JavaScript?

Quel est le moyen le plus simple/le plus propre d'implémenter un motif singleton en JavaScript?

264
Jakub Arnold

Je pense que le moyen le plus simple est de déclarer un littéral d'objet simple:

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};

Si vous voulez des membres privés sur votre instance singleton, vous pouvez faire quelque chose comme ceci:

var myInstance = (function() {
  var privateVar = '';

  function privateMethod () {
    // ...
  }

  return { // public interface
    publicMethod1: function () {
      // all private members are accesible here
    },
    publicMethod2: function () {
    }
  };
})();

Cela a été appelé the module pattern, il permet fondamentalement d'encapsuler des membres privés sur un objet, en tirant parti de l'utilisation de closures .

293
CMS

Je pense que l'approche la plus propre est quelque chose comme:

var SingletonFactory = (function(){
    function SingletonClass() {
        //do stuff
    }
    var instance;
    return {
        getInstance: function(){
            if (instance == null) {
                instance = new SingletonClass();
                // Hide the constructor so the returned object can't be new'd...
                instance.constructor = null;
            }
            return instance;
        }
   };
})();

Ensuite, vous pouvez appeler la fonction en tant que

var test = SingletonFactory.getInstance();
157
sebarmeli

Je ne suis pas sûr d’être d’accord avec le motif de module utilisé pour remplacer un motif de singleton. J'ai souvent vu des singletons utilisés et maltraités dans des endroits où ils étaient totalement inutiles, et je suis sûr que le modèle de module comble de nombreuses lacunes où les programmeurs utiliseraient autrement un singleton, mais le modèle de module est not a singleton.

modèle de module:

var foo = (function () {
    "use strict";
    function aPrivateFunction() {}
    return { aPublicFunction: function () {...}, ... };
}());

Tout ce qui est initialisé dans le modèle de module se produit lorsque Foo est déclaré. De plus, le modèle de module peut être utilisé pour initialiser un constructeur, qui pourrait ensuite être instancié plusieurs fois. Bien que le modèle de module soit le bon outil pour de nombreux travaux, il n’est pas équivalent à un singleton.

motif singleton:

forme abrégée
var Foo = function () {
    "use strict";
    if (Foo._instance) {
        //this allows the constructor to be called multiple times
        //and refer to the same instance. Another option is to
        //throw an error.
        return Foo._instance;
    }
    Foo._instance = this;
    //Foo initialization code
};
Foo.getInstance = function () {
    "use strict";
    return Foo._instance || new Foo();
}
forme longue, en utilisant le modèle de module
var Foo = (function () {
    "use strict";
    var instance; //prevent modification of "instance" variable
    function Singleton() {
        if (instance) {
            return instance;
        }
        instance = this;
        //Singleton initialization code
    }
    //instance accessor
    Singleton.getInstance = function () {
        return instance || new Singleton();
    }
    return Singleton;
}());

Dans les deux versions du motif Singleton que j'ai fourni, le constructeur lui-même peut être utilisé comme accesseur:

var a,
    b;
a = new Foo(); //constructor initialization happens here
b = new Foo();
console.log(a === b); //true

Si vous ne vous sentez pas à l'aise avec le constructeur de cette façon, vous pouvez générer une erreur dans l'instruction if (instance) et vous en tenir à la forme longue:

var a,
    b;
a = Foo.getInstance(); //constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); //true

Je devrais également mentionner que le modèle singleton s’accorde bien avec le modèle de fonction constructeur implicite:

function Foo() {
    if (Foo._instance) {
        return Foo._instance;
    }
    //if the function wasn't called as a constructor,
    //call it as a constructor and return the result
    if (!(this instanceof Foo)) {
        return new Foo();
    }
    Foo._instance = this;
}
var f = new Foo(); //calls Foo as a constructor
-or-
var f = Foo(); //also calls Foo as a constructor
95
zzzzBov

Il existe plusieurs façons de traiter un chat :) Selon votre goût ou vos besoins, vous pouvez appliquer l'une des solutions proposées. Personnellement, je préfère la première solution de CMS (lorsque vous n’avez pas besoin de confidentialité). Puisque la question portait sur le plus simple et le plus propre, c'est le gagnant. Ou même:

var myInstance = {}; // done!

Ceci (citation de mon blog) ...

var SingletonClass = new function() { 
    this.myFunction() { 
        //do stuff 
    } 
    this.instance = 1; 
}

n'a pas beaucoup de sens (mon exemple de blog non plus) car il n'a pas besoin de vars privés, donc c'est à peu près la même chose que:

var SingletonClass = { 
    myFunction: function () { 
        //do stuff 
    },
    instance: 1 
}
8
Stoyan

Je déconseille ma réponse, voir mon autre .

Généralement, le modèle de module (voir la réponse du CMS) qui n'est PAS un modèle singleton est suffisant. Cependant, une des caractéristiques de singleton est que son initialisation est retardée jusqu'à ce que l'objet soit nécessaire. Le modèle de module manque de cette fonctionnalité.

Ma proposition (CoffeeScript):

window.singleton = (initializer) ->
  instance = undefined
  () ->
    return instance unless instance is undefined
    instance = initializer()

Qui compilé à ceci en JavaScript:

window.singleton = function(initializer) {
    var instance;
    instance = void 0;
    return function() {
        if (instance !== void 0) {
            return instance;
        }
        return instance = initializer();
    };
};

Ensuite, je peux faire ce qui suit:

window.iAmSingleton = singleton(function() {
    /* This function should create and initialize singleton. */
    alert("creating");
    return {property1: 'value1', property2: 'value2'};
});


alert(window.iAmSingleton().property2); // "creating" will pop up; then "value2" will pop up
alert(window.iAmSingleton().property2); // "value2" will pop up but "creating" will not
window.iAmSingleton().property2 = 'new value';
alert(window.iAmSingleton().property2); // "new value" will pop up
7
skalee

J'ai obtenu cet exemple dans le livre de JavaScript PatternsBuild Better Applications with Coding and Design PatternsBy Stoyan Stefanov } au cas où vous auriez besoin d'une classe d'implémentation simple comme un objet unique, vous pouvez utiliser la fonction immédiate comme suit:

var ClassName;

(function() {
    var instance;
    ClassName = function ClassName() {
        //If private instance variable already initialized return reference
        if(instance) {
            return instance;   
        }
        //If instance does not created save pointer of original reference
        //to private instance variable. 
        instance = this;

        //All constructor initialization will be here
        // i.e.: 
        this.someProperty = 0;
        this.someMethod = function() {
            //Some action here
        };
    };
}());

Et vous pouvez vérifier cet exemple en suivant le cas de test:

//Extending defined class like Singltone object using new prototype property
ClassName.prototype.nothing = true;
var obj_1 = new ClassName();
//Extending defined class like Singltone object using new prototype property
ClassName.prototype.everything = true; 
var obj_2 = new ClassName();

//Testing does this two object pointing to same instance
console.log(obj_1 === obj_2); //Result is true, it points to same instance object

//All prototype properites work
//no matter when they were defined
console.log(obj_1.nothing && obj_1.everything 
            && obj_2.nothing && obj_2.everything); //Result true


//Values of properties which is defined inside of constructor
console.log(obj_1.someProperty);// output 0
console.log(obj_2.someProperty);// output 0 
//Changing property value 
obj_1.someProperty = 1;

console.log(obj_1.someProperty);// output 1
console.log(obj_2.someProperty);// output 1

console.log(obj_1.constructor === ClassName); //Output true 

Cette approche réussit tous les cas de test alors que l'implémentation statique privée échouera si une extension de prototype est utilisée (elle peut être corrigée mais ce ne sera pas simple) et une implémentation statique publique moins recommandée en raison de l'instance exposée au public.

jsFiddly demo.

6
Khamidulla

Réponse courte:

En raison de la nature non bloquante de JavaScript, les singletons en JavaScript sont vraiment laids. Les variables globales vous donneront une instance dans l’application tout entière sans tous ces rappels, le modèle de module cache doucement les éléments internes derrière l’interface. Voir la réponse @CMS.

Mais puisque tu voulais un singleton…

var singleton = function(initializer) {

  var state = 'initial';
  var instance;
  var queue = [];

  var instanceReady = function(createdInstance) {
    state = 'ready';
    instance = createdInstance;
    while (callback = queue.shift()) {
      callback(instance);
    }
  };

  return function(callback) {
    if (state === 'initial') {
      state = 'waiting';
      queue.Push(callback);
      initializer(instanceReady);
    } else if (state === 'waiting') {
      queue.Push(callback);
    } else {
      callback(instance);
    }
  };

};

Usage:

var singletonInitializer = function(instanceReady) {
  var preparedObject = {property: 'value'};
  // calling instanceReady notifies singleton that instance is ready to use
  instanceReady(preparedObject);
}
var s = singleton(singletonInitializer);

// get instance and use it
s(function(instance) {
  instance.doSomething();
});

Explication:

Les singletons vous donnent plus d’une instance par application: leur initialisation est retardée jusqu’à la première utilisation. C'est vraiment important lorsque vous traitez avec des objets dont l'initialisation est coûteuse. Cher signifie généralement E/S et en JavaScript, E/S signifie toujours des rappels.

Ne vous fiez pas aux réponses qui vous donnent une interface comme instance = singleton.getInstance(), elles passent à côté de l'essentiel.

S'ils ne prennent pas de rappel pour être exécutés lorsque l'instance est prête, ils ne fonctionneront pas si l'initialiseur effectue des E/S. 

Oui, les callbacks sont toujours plus laids que les appels de fonctions qui renvoient immédiatement une instance d'objet. Mais encore une fois: lorsque vous effectuez des E/S, les rappels sont obligatoires. Si vous ne souhaitez effectuer aucune E/S, l'instanciation est suffisamment économique pour le faire au début du programme.

Exemple 1, initialiseur bon marché:

var simpleInitializer = function(instanceReady) {
  console.log("Initializer started");
  instanceReady({property: "initial value"});
}

var simple = singleton(simpleInitializer);

console.log("Tests started. Singleton instance should not be initalized yet.");

simple(function(inst) {
  console.log("Access 1");
  console.log("Current property value: " + inst.property);
  console.log("Let's reassign this property");
  inst.property = "new value";
});
simple(function(inst) {
  console.log("Access 2");
  console.log("Current property value: " + inst.property);
});

Exemple 2, initialisation avec E/S:

Dans cet exemple, setTimeout simule une opération d’E/S coûteuse. Ceci illustre pourquoi les singletons en JavaScript ont vraiment besoin de rappels.

var heavyInitializer = function(instanceReady) {
  console.log("Initializer started");
  var onTimeout = function() {
    console.log("Initializer did his heavy work");
    instanceReady({property: "initial value"});
  };
  setTimeout(onTimeout, 500);
};

var heavy = singleton(heavyInitializer);

console.log("In this example we will be trying");
console.log("to access singleton twice before it finishes initialization.");

heavy(function(inst) {
  console.log("Access 1");
  console.log("Current property value: " + inst.property);
  console.log("Let's reassign this property");
  inst.property = "new value";
});

heavy(function(inst) {
  console.log("Access 2. You can see callbacks order is preserved.");
  console.log("Current property value: " + inst.property);
});

console.log("We made it to the end of the file. Instance is not ready yet.");
5
skalee

Je pense avoir trouvé le moyen le plus propre de programmer en JavaScript, mais vous aurez besoin d'un peu d'imagination. J'ai eu cette idée d'une technique de travail dans le livre "javascript the good parts".

Au lieu d'utiliser le nouveau mot-clé, vous pouvez créer une classe comme celle-ci:

function Class()
{
    var obj = {}; // Could also be used for inheritence if you don't start with an empty object.

    var privateVar;
    obj.publicVar;

    obj.publicMethod= publicMethod;
    function publicMethod(){} 

    function privateMethod(){} 

    return obj;
}

Vous pouvez instancier l'objet ci-dessus en disant:

var objInst = Class(); // !!! NO NEW KEYWORD

Maintenant, avec cette méthode de travail en tête, vous pouvez créer un singleton comme ceci:

ClassSingleton = function()
{
    var instance= null;

    function Class() // This is the class like the above one
    {
        var obj = {};
        return obj;
    }

    function getInstance()
    {
        if( !instance )
            instance = Class(); // Again no new keyword;

        return instance;
    }   

    return { getInstance : getInstance };

}();

Maintenant, vous pouvez obtenir votre instance en appelant

var obj = ClassSingleton.getInstance();

Je pense que c'est la meilleure façon, car la "classe" complète n'est même pas accessible. 

5
David

La réponse la plus claire devrait être celle du livre Learning JavaScript Design Patterns de Addy Osmani.

var mySingleton = (function () {
 
  // Instance stores a reference to the Singleton
  var instance;
 
  function init() {
 
    // Singleton
 
    // Private methods and variables
    function privateMethod(){
        console.log( "I am private" );
    }
 
    var privateVariable = "Im also private";
 
    var privateRandomNumber = Math.random();
 
    return {
 
      // Public methods and variables
      publicMethod: function () {
        console.log( "The public can see me!" );
      },
 
      publicProperty: "I am also public",
 
      getRandomNumber: function() {
        return privateRandomNumber;
      }
 
    };
 
  };
 
  return {
 
    // Get the Singleton instance if one exists
    // or create one if it doesn't
    getInstance: function () {
 
      if ( !instance ) {
        instance = init();
      }
 
      return instance;
    }
 
  };
 
})();

4
令狐葱

@CMS et @zzzzBov ont tous deux donné de merveilleuses réponses, mais je voudrais juste ajouter ma propre interprétation basée sur le fait que je suis passé au développement lourd de node.js à partir de PHP/Zend Framework où les modèles singleton étaient courants.

Le code de commentaire commenté suivant est basé sur les exigences suivantes:

  • une et une seule instance de l'objet fonction peut être instanciée
  • l'instance n'est pas accessible au public et n'est accessible que par une méthode publique
  • le constructeur n'est pas disponible publiquement et ne peut être instancié que s'il n'y a pas déjà d'instance disponible
  • la déclaration du constructeur doit permettre de modifier son prototype de chaîne. Cela permettra au constructeur d’hériter d’autres prototypes et d’offrir des méthodes "publiques" pour l’instance.

Mon code est très similaire à @ zzzzBov, sauf que j'ai ajouté une chaîne de prototypes au constructeur et plus de commentaires qui devraient aider ceux venant de PHP ou un langage similaire à traduire le traditionnel OOP en prototypique à la nature. Ce n'est peut-être pas le "plus simple" mais je crois que c'est le plus approprié.

// declare 'Singleton' as the returned value of a self-executing anonymous function
var Singleton = (function () {
    "use strict";
    // 'instance' and 'constructor' should not be availble in a "public" scope
    // here they are "private", thus available only within 
    // the scope of the self-executing anonymous function
    var _instance=null;
    var _constructor = function (name) {
        this.name = name || 'default';
    }

    // prototypes will be "public" methods available from the instance
    _constructor.prototype.getName = function () {
        return this.name;
    }

    // using the module pattern, return a static object
    // which essentially is a list of "public static" methods
    return {
        // because getInstance is defined within the same scope
        // it can access the "private" 'instance' and 'constructor' vars
        getInstance:function (name) {
            if (!_instance) {
                console.log('creating'); // this should only happen once
                _instance = new _constructor(name);
            }
            console.log('returning');
            return _instance;
        }
    }

})(); // self execute

// ensure 'instance' and 'constructor' are unavailable 
// outside the scope in which they were defined
// thus making them "private" and not "public"
console.log(typeof _instance); // undefined
console.log(typeof _constructor); // undefined

// assign instance to two different variables
var a = Singleton.getInstance('first');
var b = Singleton.getInstance('second'); // passing a name here does nothing because the single instance was already instantiated

// ensure 'a' and 'b' are truly equal
console.log(a === b); // true

console.log(a.getName()); // "first"
console.log(b.getName()); // also returns "first" because it's the same instance as 'a'

Notez que techniquement, la fonction anonyme à exécution automatique est elle-même un Singleton, comme le montre bien le code fourni par @CMS. Le seul problème ici est qu'il n'est pas possible de modifier la chaîne de prototypes du constructeur lorsque le constructeur lui-même est anonyme.

N'oubliez pas qu'en Javascript, les concepts de «public» et de «privé» ne s'appliquent pas comme ils le sont dans PHP ou en Java. Mais nous avons obtenu le même effet en exploitant les règles de disponibilité de la portée fonctionnelle de Javascript.

4
talentedmrjones

Vous ne savez pas pourquoi personne n'en a parlé, mais vous pouvez simplement faire:

var singleton = new (function() {
  var bar = 123

  this.foo = function() {
    // whatever
  }
})()
4
Derek Chiang

puis-je mettre mes 5 pièces? J'ai une fonction constructeur, ex. 

var A = function(arg1){
  this.arg1 = arg1  
};

Ce que je dois faire, c’est que chaque objet créé par ce FC sera identique.

var X = function(){
  var instance = {};
  return function(){ return instance; }
}();

tester

var x1 = new X();
var x2 = new X();
console.log(x1 === x2)
2
Olencha

Ce qui suit fonctionne dans le noeud v6

class Foo {
  constructor(msg) {

    if (Foo.singleton) {
      return Foo.singleton;
    }

    this.msg = msg;
    Foo.singleton = this;
    return Foo.singleton;
  }
}

Nous testons:

const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }
2
Daniel

Voici l'exemple simple pour expliquer le modèle singleton dans un script Java.

 var Singleton=(function(){
      var instance;
      var init=function(){
           return {
             display:function(){
             alert("This is a Singleton patern demo");
              }
            };
           }; 
            return {
              getInstance:function(){
                   if(!instance){
                     alert("Singleton check");
                      instance=init();
                       }
               return instance;
             }
         };

    })();

   // In this call first display alert("Singleton check")
  // and then alert("This is a Singleton patern demo");
  // It means one object is created

    var inst=Singleton.getInstance();
    inst.display();

    // In this call only display alert("This is a Singleton patern demo")
   //  it means second time new object is not created, 
   //  it uses the already created object 

    var inst1=Singleton.getInstance();
    inst1.display();
2
Sheo Dayal Singh

J'ai trouvé que le modèle Singleton suivant était le plus simple, car utiliser l'opérateur new operator rend this immédiatement disponible dans la fonction, ce qui élimine la nécessité de renvoyer un objet littéral:

var singleton = new (function () {

  var private = "A private value";
  
  this.printSomething = function() {
      console.log(private);
  }
})();

singleton.printSomething();

2
Mark

Vous pouvez le faire avec des décorateurs comme dans l'exemple ci-dessous pour TypeScript:

class YourClass {

    @Singleton static singleton() {}

}

function Singleton(target, name, descriptor) {
    var instance;
    descriptor.value = () => {
        if(!instance) instance = new target;
        return instance;
    };
}

Ensuite, vous utilisez votre singleton comme ceci:

var myInstance = YourClass.singleton();

A ce jour, les décorateurs ne sont pas facilement disponibles dans les moteurs JavaScript. Vous devez vous assurer que les décorateurs sont bien activés dans votre runtime JavaScript ou utiliser des compilateurs tels que Babel et TypeScript.

Notez également que l’instance singleton est créée "paresseuse", c’est-à-dire qu’elle est créée uniquement lorsque vous l’utilisez pour la première fois.

1
Vad

voici l'extrait de ma marche pour implémenter un motif singleton. Cela m’est venu à l’esprit lors d’un processus d’entrevue et j’ai senti que je devais capturer cela quelque part.

/*************************************************
   *     SINGLETON PATTERN IMPLEMENTATION          *
   *************************************************/

  //since there are no classes in javascript, every object is technically a singleton
  //if you don't inherit from it or copy from it.
  var single = {};
  //Singleton Implementations
  //Declaring as a Global Object...you are being judged!


  var Logger = function() {
    //global_log is/will be defined in GLOBAL scope here
    if(typeof global_log === 'undefined'){
      global_log = this;
    }
    return global_log;
  };


  //the below 'fix' solves the GLOABL variable problem but
  //the log_instance is publicly available and thus can be 

  //tampered with.
  function Logger() {
    if(typeof Logger.log_instance === 'undefined'){
      Logger.log_instance = this;
    }


    return Logger.log_instance;
   };


  //the correct way to do it to give it a closure!


  function logFactory() {
    var log_instance; //private instance
    var _initLog = function() { //private init method
      log_instance = 'initialized';
      console.log("logger initialized!")
    }
    return {
      getLog : function(){ //the 'privileged' method 
        if(typeof log_instance === 'undefined'){
          _initLog();
        }
        return log_instance;
      }
    };
  }

  /***** TEST CODE ************************************************
  //using the Logger singleton
  var logger = logFactory();//did i just gave LogFactory a closure?
  //create an instance of the logger
  var a = logger.getLog();
  //do some work
  //get another instance of the logger
  var b = logger.getLog();


  //check if the two logger instances are same?
  console.log(a === b); //true
  *******************************************************************/

la même chose peut être trouvée sur mon Gist page

1
curioussam

J'ai eu besoin de plusieurs singletons avec:

  • initialisation paresseuse
  • paramètres initiaux

et c’est ce que j’ai trouvé:

createSingleton ('a', 'add', [1, 2]);
console.log(a);

function createSingleton (name, construct, args) {
    window[name] = {};
    window[construct].apply(window[name], args);
    window[construct] = null;
}

function add (a, b) {
    this.a = a;
    this.b = b;
    this.sum = a + b;
}
  • args doit être Array pour que cela fonctionne, donc si vous avez des variables vides, passez simplement pass in []

  • J'ai utilisé l'objet window dans la fonction mais j'aurais pu passer un paramètre pour créer ma propre portée

  • les paramètres name et construct ne sont que String pour que window [] fonctionne, mais avec quelques vérifications de type simples, window.name et window.construct sont également possibles.

1
fred

Quel est le problème avec cela?

function Klass() {
   var instance = this;
   Klass = function () { return instance; }
}
1
Manav

Que diriez-vous de cette façon, assurez-vous que la classe ne peut pas recommencer.

De cette manière, vous pouvez utiliser l'opération instanceof, vous pouvez également utiliser la chaîne de prototypes pour hériter de la classe. Il s'agit d'une classe standard, mais vous ne pouvez pas la modifier si vous voulez obtenir l'instance, utilisez simplement getInstance.

function CA()
{
    if(CA.instance)
    {
        throw new Error('can not new this class');
    }else{
        CA.instance = this;
    }

}
/**
 * @protected
 * @static
 * @type {CA}
 */
CA.instance = null;
/** @static */
CA.getInstance = function()
{
    return CA.instance;
}

CA.prototype = 
/** @lends CA#*/
{
    func: function(){console.log('the func');}
}
// initilize the instance
new CA();

// test here
var c = CA.getInstance()
c.func();
console.assert(c instanceof CA)
// this will failed
var b = new CA();

Si vous ne souhaitez pas exposer le membre instance, mettez-le simplement dans une fermeture.

1
wener

Singleton:

Assurez-vous qu'une classe n'a qu'une seule instance et fournissez un point d'accès global à celle-ci.

Le modèle Singleton limite le nombre d'instances d'un objet particulier à une seule. Cette instance unique s'appelle le singleton.

  • définit getInstance () qui renvoie l'instance unique.
  • responsable de la création et de la gestion de l'objet d'instance.

L'objet Singleton est implémenté en tant que fonction anonyme immédiate. La fonction s'exécute immédiatement en la plaçant entre crochets, suivie de deux crochets supplémentaires. Cela s'appelle anonyme parce qu'il n'a pas de nom.

Exemple de programme,

var Singleton = (function () {
    var instance;
 
    function createInstance() {
        var object = new Object("I am the instance");
        return object;
    }
 
    return {
        getInstance: function () {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();
 
function run() {
 
    var instance1 = Singleton.getInstance();
    var instance2 = Singleton.getInstance();
 
    alert("Same instance? " + (instance1 === instance2));  
}

run()

1

Modèle de module: dans un "style plus lisible". Vous pouvez facilement voir quelles méthodes sont publiques et lesquelles sont privées

var module = (function(_name){
   /*Local Methods & Values*/
   var _local = {
      name : _name,
      flags : {
        init : false
      }
   }

   function init(){
     _local.flags.init = true;
   }

   function imaprivatemethod(){
     alert("hi im a private method");
   }

   /*Public Methods & variables*/

   var $r = {}; //this object will hold all public methods.

   $r.methdo1 = function(){
       console.log("method1 call it");
   }

   $r.method2 = function(){
      imaprivatemethod(); //calling private method
   }

   $r.init = function(){
      inti(); //making init public in case you want to init manually and not automatically
   }

   init(); //automatically calling init method

   return $r; //returning all publics methods

})("module");

maintenant vous pouvez utiliser des méthodes publiques comme

module.method2 (); // -> J'appelle une méthode privée via une alerte de méthode publique ("hi im a private method")

http://jsfiddle.net/ncubica/xMwS9/

1
ncubica

N'est-ce pas un singleton aussi?

function Singleton() {
    var i = 0;
    var self = this;

    this.doStuff = function () {
        i = i + 1;
        console.log( 'do stuff',i );
    };

    Singleton = function () { return self };
    return this;
}

s = Singleton();
s.doStuff();
1
Nawal
function Unicode()
  {
  var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
  //Loop through code points
  while (i < max) {
    //Convert decimal to hex value, find the character, then pad zeroes to the codepoint
    unicode[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
    i = i + 1;
    }

  //Replace this function with the resulting lookup table
  Unicode = unicode;
  }

//Usage
Unicode();
//Lookup
Unicode["%"]; //returns 0025
1
Paul Sweatte

J'aime utiliser une combinaison du Singleton avec le modèle de module, une branche init-time avec un contrôle global NS, encapsulée dans une fermeture. Dans le cas où l'environnement ne changera pas après l'initialisation du singleton; l'utilisation d'un littéral-objet immédiatement appelé pour renvoyer un module contenant des utilitaires qui persisteront pendant un certain temps devrait suffire. Je ne passe aucune dépendance, je ne fais qu'appeler les singletons dans leur propre petit monde - le seul objectif étant de: créer un module d'utilitaires pour la liaison/dé-liaison d'événements (les changements d'orientation de périphérique/d'orientation pourraient également fonctionner dans ce cas).

window.onload = ( function( _w ) {
            console.log.apply( console, ['it', 'is', 'on'] );
            ( {
                globalNS : function() {
                    var nameSpaces = ["utils", "eventUtils"],
                        nsLength = nameSpaces.length,
                        possibleNS = null;

                    outerLoop:
                    for ( var i = 0; i < nsLength; i++ ) {
                        if ( !window[nameSpaces[i]] ) {
                            window[nameSpaces[i]] = this.utils;
                            break outerLoop;
                        };
                    };
                },
                utils : {
                    addListener : null,
                    removeListener : null
                },
                listenerTypes : {
                    addEvent : function( el, type, fn ) {
                        el.addEventListener( type, fn, false );
                    },
                    removeEvent : function( el, type, fn ) {
                        el.removeEventListener( type, fn, false );
                    },
                    attachEvent : function( el, type, fn ) {
                        el.attachEvent( 'on'+type, fn );
                    },
                    detatchEvent : function( el, type, fn ) {
                        el.detachEvent( 'on'+type, fn );
                    }
                },
                buildUtils : function() {
                    if ( typeof window.addEventListener === 'function' ) {
                        this.utils.addListener = this.listenerTypes.addEvent;
                        this.utils.removeListener = this.listenerTypes.removeEvent;
                    } else {
                        this.utils.attachEvent = this.listenerTypes.attachEvent;
                        this.utils.removeListener = this.listenerTypes.detatchEvent;
                    };
                    this.globalNS();
                },
                init : function() {
                    this.buildUtils();
                }
            } ).init();
        }( window ) );
0
WHill

Je pense que c’est la manière la plus simple, la plus propre et la plus intuitive de procéder, mais elle nécessite ES7:

export default class Singleton {

  static instance;

  constructor(){
    if(instance){
      return instance;
    }

    this.state = "duke";
    this.instance = this;
  }

}

Le code source provient de: adam-bien.com

0
Alt Eisen

Singleton en javascript est obtenu à l'aide du modèle de module et des fermetures. Ci-dessous le code qui s’explique assez bien - 

// singleton example.
var singleton = (function() {
  var instance;
  function init() {
    var privateVar1 = "this is a private variable";
    var privateVar2 = "another var";
    function pubMethod() {
      //accessing private variables from inside.
      console.log(this.privateVar1);
      console.log(this.privateVar2);
      console.log("inside of a public method");
    };
  }
  function getInstance() {
    if (!instance) {
      instance = init();
    }
    return instance;
  };
  return {
    getInstance: getInstance
  }
})();


var obj1 = singleton.getInstance();
var obj2 = singleton.getInstance();

cnosole.log(obj1===obj2); //check for type and value. 
0
user2756335

Vous n'avez pas dit "dans le navigateur". Sinon, vous pouvez utiliser modules NodeJS . Ces sont les mêmes pour chaque appel require . Exemple de base:

Le contenu de foo.js:

const circle = require('./circle.js');
console.log( `The area of a circle of radius 4 is ${circle.area(4)}`);

Le contenu de circle.js:

const PI = Math.PI;

exports.area = (r) => PI * r * r;

exports.circumference = (r) => 2 * PI * r;

Notez que vous ne pouvez pas accéder à circle.PI, car il n'est pas exporté.

Bien que cela ne fonctionne pas dans le navigateur, il est simple et propre.

0
serv-inc

Pour moi, le plus simple/le plus propre signifie aussi simplement comprendre et pas de cloches et de sifflets comme cela est beaucoup discuté dans la version Java de la discussion:

Quel est un moyen efficace d'implémenter un motif singleton en Java?

La réponse qui conviendrait le mieux aux solutions les plus simples et les plus propres de mon point de vue est la suivante:

https://stackoverflow.com/a/70824/1497139

Et cela ne peut être que partiellement traduit en JavaScript. Certaines des différences en Javascript sont:

  • les constructeurs ne peuvent pas être privés
  • Les classes ne peuvent pas avoir de champs déclarés

Mais étant donné la dernière syntaxe ECMA, il est possible de se rapprocher de:

Motif Singleton comme exemple de classe JavaScript

 class Singleton {

  constructor(field1,field2) {
    this.field1=field1;
    this.field2=field2;
    Singleton.instance=this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance=new Singleton('DefaultField1','DefaultField2');
    }
    return Singleton.instance;
  }
}

Exemple d'utilisation

console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);

Exemple de résultat

DefaultField1
DefaultField2
0
Wolfgang Fahl

La clé principale est l'importance de la fermeture et de la fermeture derrière cette propriété. Ainsi, même à l'intérieur de la fonction interne, la fermeture sera privée. 

var Singleton = function () { var instance;

 function init() {

    function privateMethod() {
        console.log("private via closure");
    }

    var privateVariable = "Private Property";

    var privateRandomNumber = Math.random();// this also private

    return {
        getRandomNumber: function () {  // access via getter in init call
            return privateRandomNumber;
        }

    };

};

return {
    getInstance: function () {

        if (!instance) {
            instance = init();
        }

        return instance;
    }

};

};

0
Siddhartha
function Once() {
    return this.constructor.instance || (this.constructor.instance = this);
}

function Application(name) {
    let app = Once.call(this);

    app.name = name;

    return app;
}

Si vous êtes dans les cours:

class Once {
    constructor() {
        return this.constructor.instance || (this.constructor.instance = this);
    }
}

class Application extends Once {
    constructor(name) {
        super();

        this.name = name;
    }
}

Tester:

console.log(new Once() === new Once());

let app1 = new Application('Foobar');
let app2 = new Application('Barfoo');

console.log(app1 === app2);
console.log(app1.name); // Barfoo
0
frasq

Vous pouvez renvoyer la même instance à chaque exécution de new

function Singleton() {
    // lazy 
    if (Singleton.prototype.myInstance == undefined) {
        Singleton.prototype.myInstance = { description: "I am the instance"};
    }
    return Singleton.prototype.myInstance;
}

a = new Singleton();
b = new Singleton();
console.log(a); // { description: "I am the instance"};
console.log(b); // { description: "I am the instance"};
console.log(a==b); // true
0
URL87