469 votes

Façon la plus simple / la plus propre d'implémenter singleton en JavaScript?

Quelle est la manière la plus simple / la plus propre d'implémenter un pattern singleton en JavaScript?

397voto

CMS Points 315406

Je pense que le plus simple est de déclarer un objet simple littérale:

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

Si vous voulez privé des membres de votre instance du 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 () {
    }
  };
})();

Ce qui a été appelé le motif de module, il permet d'encapsuler les membres privés sur un objet, en prenant avantage de l'utilisation de fermetures.

215voto

sebarmeli Points 11831

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

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

Ensuite, vous pouvez appeler la fonction

 var test = SingletonClass.getInstance();
 

124voto

zzzzBov Points 62084

Je ne suis pas sûr que je suis d'accord avec le motif de module utilisé comme un remplacement pour le pattern singleton. J'ai souvent vu des singletons utilisé et abusé dans des endroits où ils sont totalement inutiles, et je suis sûr que le motif de module remplit de nombreuses lacunes dans les cas où les programmeurs sinon utiliser un singleton, cependant le motif de module n'est pas un singleton.

motif de module:

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

Tout initialisé dans le motif de module qui se passe quand Foo est déclarée. En outre, le motif de module peut être utilisé pour initialiser un constructeur, qui pourrait ensuite être instancié plusieurs fois. Alors que le motif de module est le bon outil pour de nombreux emplois, il n'est pas équivalent à un singleton.

le pattern singleton:

forme courte
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, à l'aide du module de modèle
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 pattern Singleton que j'ai fourni, le constructeur lui-même peut être utilisé comme l'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 d'utiliser le constructeur de cette façon, vous pouvez jeter une erreur dans l' if (instance) déclaration, et le bâton à l'aide du formulaire:

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

Je devrais aussi mentionner que le pattern singleton colle bien avec l'implicite de la fonction de constructeur modèle:

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

7voto

Stoyan Points 341

Il y a plus d'une façon à la peau d'un chat :) Selon votre goût ou à besoins spécifiques, vous pouvez appliquer l'une des solutions proposées. Personnellement, je aller pour la CMS première solution chaque fois que possible (lorsque vous n'avez pas besoin de confidentialité). Depuis que la question a été sur le plus simple et le plus propre, c'est le vainqueur. Ou encore:

var myInstance = {}; // done!

Ce (citation de mon blog) ...

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

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

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

7voto

skalee Points 3227

Je railler ma réponse, voir mes autre.

Généralement motif de module (voir CMS réponse) ce qui n'est PAS le pattern singleton est assez bon. Cependant, l'une des caractéristiques de singleton est que son initialisation est retardée jusqu'objet est nécessaire. Motif de Module ne le permet pas.

Ma proposition (CoffeeScript):

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

Qui a compilé pour cela en JavaScript:

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

Alors je peux le faire à la suite:

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

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