Quelle est la manière la plus simple / la plus propre d'implémenter un pattern singleton en JavaScript?
Réponses
Trop de publicités?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.
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();
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 courtevar 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èlevar 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
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
}
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