Jaki jest najprostszy / najczystszy sposób zaimplementowania wzorca singleton w JavaScript?
Jaki jest najprostszy / najczystszy sposób zaimplementowania wzorca singleton w JavaScript?
Odpowiedzi:
Myślę, że najłatwiej jest zadeklarować prosty dosłowny obiekt:
var myInstance = {
method1: function () {
// ...
},
method2: function () {
// ...
}
};
Jeśli chcesz członków prywatnych w swojej instancji singleton, możesz zrobić coś takiego:
var myInstance = (function() {
var privateVar = '';
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// all private members are accessible here
},
publicMethod2: function () {
}
};
})();
Nazywa się to wzorcem modułowym i zasadniczo pozwala enkapsulować prywatne elementy na obiekcie, wykorzystując zamknięcia .
AKTUALIZACJA: Chciałbym dodać, że jeśli chcesz zapobiec modyfikacji obiektu singletonu, możesz go zatrzymać , używając Object.freeze
metody ES5 .
To sprawi, że obiekt będzie niezmienny, zapobiegając jakiejkolwiek modyfikacji jego struktury i wartości.
Dodatkowo chciałbym wspomnieć, że jeśli używasz ES6, możesz bardzo łatwo reprezentować singletona za pomocą ES Modules , a nawet możesz utrzymywać stan prywatny , deklarując zmienne w zakresie modułu :
// my-singleton.js
const somePrivateState = []
function privateFn () {
// ...
}
export default {
method1() {
// ...
},
method2() {
// ...
}
}
Następnie możesz po prostu zaimportować obiekt singleton, aby go użyć:
import myInstance from './my-singleton.js'
// ...
publicMethod1
zadzwonił publicMethod2
?
getInstance
metodę statyczną i prywatnego konstruktora - ale IMO to najprostszy sposób na zbudowanie obiektu singleton w JavaScript, a na koniec spełnia ten sam cel - pojedynczy obiekt, którego nie można ponownie zainicjować (nie ma konstruktora, to tylko obiekt) -. Jeśli chodzi o kod, który podłączyłeś, ma on pewne problemy, zamienia a
i b
deklaruje zmienne i testuje a === window
. Twoje zdrowie.
Myślę, że najczystsze podejście to:
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;
}
};
})();
Następnie możesz wywołać funkcję as
var test = SingletonFactory.getInstance();
delete instance.constructor
:x = SingletonClass.getInstance();delete x.constructor;new x.constructor;
Nie jestem pewien, czy zgadzam się na użycie wzorca modułu jako zamiennika wzorca singletonu. Często widziałem singletony używane i nadużywane w miejscach, w których są całkowicie niepotrzebne, i jestem pewien, że wzór modułu wypełnia wiele luk, w których programiści używaliby singletonu, jednak wzór modułu nie jest singletonem.
var foo = (function () {
"use strict";
function aPrivateFunction() {}
return { aPublicFunction: function () {...}, ... };
}());
Wszystko zainicjowane we wzorcu modułu dzieje się, gdy Foo
zostanie zadeklarowane. Ponadto wzorca modułu można użyć do zainicjowania konstruktora, który można następnie utworzyć wiele razy. Chociaż wzorzec modułu jest właściwym narzędziem do wielu zadań, nie jest równoważny z singletonem.
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();
}
długa forma, przy użyciu wzoru modułu
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;
}());
W obu wersjach wzorca Singleton, który podałem, sam konstruktor może być używany jako akcesorium:
var a,
b;
a = new Foo(); //constructor initialization happens here
b = new Foo();
console.log(a === b); //true
Jeśli nie czujesz się komfortowo przy użyciu konstruktora w ten sposób, możesz zgłosić błąd w if (instance)
instrukcji i trzymać się długiej formy:
var a,
b;
a = Foo.getInstance(); //constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); //true
Powinienem również wspomnieć, że wzorzec singletonu dobrze pasuje do domyślnego wzorca funkcji konstruktora:
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
var singleton = {}
nie pasuje do tej definicji.
var singleton = {}
jest jak zaimplementować singleton w JavaScript .
W es6
:
class Singleton {
constructor () {
if (!Singleton.instance) {
Singleton.instance = this
}
// Initialize object
return Singleton.instance
}
// Properties & Methods
}
const instance = new Singleton()
Object.freeze(instance)
export default instance
instance
pole. Ponieważ jest obecnie ( instance
ustawiona na this
) ta klasa może mieć także inne pola, a zamrażanie nie ma sensu.
Następujące działa w węźle v6
class Foo {
constructor(msg) {
if (Foo.singleton) {
return Foo.singleton;
}
this.msg = msg;
Foo.singleton = this;
return Foo.singleton;
}
}
Testujemy:
const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }
W ES6 właściwym sposobem na to jest:
class MyClass {
constructor() {
if (MyClass._instance) {
throw new Error("Singleton classes can't be instantiated more than once.")
}
MyClass._instance = this;
// ... your rest of the constructor code goes after this
}
}
var instanceOne = new MyClass() // Executes succesfully
var instanceTwo = new MyClass() // Throws error
Lub jeśli nie chcesz, aby błąd był generowany podczas tworzenia drugiej instancji, możesz po prostu zwrócić ostatnią instancję w następujący sposób:
class MyClass {
constructor() {
if (MyClass._instance) {
return MyClass._instance
}
MyClass._instance = this;
// ... your rest of the constructor code goes after this
}
}
var instanceOne = new MyClass()
var instanceTwo = new MyClass()
console.log(instanceOne === instanceTwo) // logs "true"
instance
i _instance
. To tylko konwencja nazewnictwa w językach programowania, którą nazywamy zmiennymi prywatnymi poprzedzonymi znakiem podkreślenia. Podejrzewam, że przyczyną tego, że Twój kod nie działa, jest to, że używasz this.instance
zamiastMyClass.instance
Jest więcej niż jeden sposób na skórowanie kota :) W zależności od gustu lub konkretnej potrzeby możesz zastosować dowolne z proponowanych rozwiązań. Osobiście wybieram pierwsze rozwiązanie CMS, gdy tylko jest to możliwe (gdy nie potrzebujesz prywatności). Ponieważ pytanie dotyczyło najprostszego i najczystszego, to jest zwycięzca. Lub nawet:
var myInstance = {}; // done!
To (cytat z mojego bloga) ...
var SingletonClass = new function() {
this.myFunction() {
//do stuff
}
this.instance = 1;
}
nie ma większego sensu (mój przykład na blogu też nie), ponieważ nie potrzebuje żadnych prywatnych zmiennych, więc jest prawie taki sam jak:
var SingletonClass = {
myFunction: function () {
//do stuff
},
instance: 1
}
this.f(){}
Nie zgadzam się z moją odpowiedzią, zobacz moją drugą .
Zwykle wzorzec modułu (patrz odpowiedź CMS), który NIE jest wzorzec singletonu, jest wystarczająco dobry. Jednak jedną z cech singletonu jest to, że jego inicjalizacja jest opóźniona do momentu, gdy potrzebny jest obiekt. Wzorzec modułu nie ma tej funkcji.
Moja propozycja (CoffeeScript):
window.singleton = (initializer) ->
instance = undefined
() ->
return instance unless instance is undefined
instance = initializer()
Które skompilowane do tego w JavaScript:
window.singleton = function(initializer) {
var instance;
instance = void 0;
return function() {
if (instance !== void 0) {
return instance;
}
return instance = initializer();
};
};
Następnie mogę wykonać następujące czynności:
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
Ponieważ nieblokujący charakter JavaScript, Singletons w JavaScript są naprawdę brzydkie w użyciu. Zmienne globalne dają również jedną instancję w całej aplikacji bez tych wszystkich wywołań zwrotnych, wzór modułu delikatnie ukrywa elementy wewnętrzne za interfejsem. Zobacz odpowiedź @CMS.
Ale skoro chciałeś singletona…
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);
}
};
};
Stosowanie:
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();
});
Singletony dają więcej niż jedną instancję w całej aplikacji: ich inicjalizacja jest opóźniona do pierwszego użycia. To naprawdę wielka sprawa, gdy masz do czynienia z obiektami, których inicjalizacja jest droga. Drogie zwykle oznacza We / Wy, aw JavaScript We / Wy zawsze oznacza oddzwanianie.
Nie ufaj odpowiedziom, które dają ci interfejs instance = singleton.getInstance()
, wszystkie pomijają sens.
Jeśli nie przyjmą wywołania zwrotnego do uruchomienia, gdy instancja jest gotowa, nie będą działać, gdy inicjator wykonuje operacje we / wy.
Tak, wywołania zwrotne zawsze wyglądają brzydiej niż wywołanie funkcji, które natychmiast zwraca instancję obiektu. Ale znowu: kiedy wykonujesz operacje we / wy, połączenia zwrotne są obowiązkowe. Jeśli nie chcesz wykonywać żadnych operacji we / wy, tworzenie instancji jest wystarczająco tanie, aby zrobić to na początku programu.
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);
});
W tym przykładzie setTimeout
podróbka kosztownej operacji we / wy. To pokazuje, dlaczego singletony w JavaScript naprawdę potrzebują wywołań zwrotnych.
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.");
Ten przykład wziąłem z wzorców JavaScript, które budują lepsze aplikacje z kodowaniem i wzorami projektowymi. Książka Stoyana Stefanova na wypadek, gdybyś potrzebował prostej klasy implementacji, takiej jak obiekt singltone, możesz użyć natychmiastowej funkcji:
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
};
};
}());
Możesz sprawdzić ten przykład, wykonując następujący 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
Podejście to przechodzi wszystkie przypadki testowe, podczas gdy prywatna implementacja statyczna zakończy się niepowodzeniem, gdy zostanie użyte rozszerzenie prototypu (można to naprawić, ale nie będzie to proste), a publiczna implementacja statyczna mniej wskazana z powodu wystąpienia jest ujawniana publicznie.
Myślę, że znalazłem najczystszy sposób na programowanie w JavaScript, ale potrzebujesz wyobraźni. Ten pomysł zaczerpnąłem z techniki pracy w książce „javascript the good parts”.
Zamiast używać nowego słowa kluczowego, możesz utworzyć taką klasę:
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;
}
Możesz utworzyć instancję powyższego obiektu, mówiąc:
var objInst = Class(); // !!! NO NEW KEYWORD
Teraz mając na uwadze tę metodę pracy, możesz utworzyć singleton taki jak ten:
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 };
}();
Teraz możesz uzyskać instancję, dzwoniąc
var obj = ClassSingleton.getInstance();
Myślę, że to najładniejszy sposób, ponieważ cała „klasa” nie jest nawet dostępna.
Zarówno @CMS, jak i @zzzzBov dały wspaniałe odpowiedzi, ale tylko po to, by dodać własną interpretację opartą na tym, że przeszedłem do ciężkiego rozwoju node.js z PHP / Zend Framework, w którym wzorce singletonów były powszechne.
Poniższy kod udokumentowany komentarzem opiera się na następujących wymaganiach:
Mój kod jest bardzo podobny do kodu @ zzzzBov, z tym wyjątkiem, że dodałem do konstruktora łańcuch prototypów i więcej komentarzy, które powinny pomóc osobom pochodzącym z PHP lub podobnego języka w przetłumaczeniu tradycyjnego OOP na JavaScript o charakterze prototypowym. Może nie jest to „najprostsze”, ale uważam, że jest najbardziej odpowiednie.
// 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'
Zauważ, że technicznie samoczynnie wykonująca się funkcja anonimowa sama w sobie jest Singletonem, co dobrze pokazano w kodzie dostarczonym przez @CMS. Jedynym haczykiem jest to, że nie można modyfikować łańcucha prototypów konstruktora, gdy sam konstruktor jest anonimowy.
Pamiętaj, że w przypadku Javascript pojęcia „public” i „private” nie mają zastosowania, tak jak w PHP lub Javie. Ale osiągnęliśmy ten sam efekt, wykorzystując zasady dostępności zakresu funkcjonalnego Javascript.
var a = Singleton.getInstance('foo'); var b = new a.constructor('bar');
Nie jestem pewien, dlaczego nikt tego nie poruszał, ale możesz po prostu:
var singleton = new (function() {
var bar = 123
this.foo = function() {
// whatever
}
})()
Najjaśniejszą odpowiedzią powinna być ta z książki Uczenie się wzorców projektowania JavaScript autorstwa 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;
}
};
})();
Uważam, że jest to najprostszy / najczystszy i najbardziej intuicyjny sposób, choć wymaga ES7:
export default class Singleton { static instance; constructor(){ if(instance){ return instance; } this.state = "duke"; this.instance = this; } }
Kod źródłowy pochodzi z: adam-bien.com
new Singleton()
czy mogę włożyć moje 5 monet. Mam funkcję konstruktora, np.
var A = function(arg1){
this.arg1 = arg1
};
Muszę tylko każdy obiekt utworzony przez ten CF będzie taki sam.
var X = function(){
var instance = {};
return function(){ return instance; }
}();
test
var x1 = new X();
var x2 = new X();
console.log(x1 === x2)
Odkryłem, że jest to najłatwiejszy wzorzec Singleton, ponieważ użycie nowego operatora powoduje, że jest on natychmiast dostępny w ramach funkcji, co eliminuje potrzebę zwracania literału obiektu:
var singleton = new (function () {
var private = "A private value";
this.printSomething = function() {
console.log(private);
}
})();
singleton.printSomething();
Oto prosty przykład wyjaśniający wzór singletonu w javascript.
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();
Potrzebowałem kilku singletonów z:
i tak oto wpadłem na pomysł:
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;
}
Argumenty muszą być tablicą, aby to działało, więc jeśli masz puste zmienne, po prostu przekaż []
Użyłem obiektu window w funkcji, ale mogłem przekazać parametr, aby utworzyć własny zakres
parametry nazwy i konstrukcji są tylko ciągiem, aby okno [] działało, ale przy prostym sprawdzaniu typów możliwe jest także window.name i window.construct.
A co powiesz na ten sposób, po prostu upewnij się, że klasa nie będzie znowu nowa.
Dzięki temu możesz użyć instanceof
op, możesz także użyć łańcucha prototypów, aby odziedziczyć klasę, jest to zwykła klasa, ale nie możesz jej nowego, jeśli chcesz uzyskać instancję, użyjgetInstance
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();
Jeśli nie chcesz narażać instance
członka, po prostu zamknij go.
Poniżej znajduje się fragment mojego przejścia do implementacji wzorca singletonu. To przyszło mi do głowy podczas wywiadu i czułem, że powinienem to gdzieś uchwycić.
/*************************************************
* 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
*******************************************************************/
to samo można znaleźć na moim GIST stronie
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
Możesz to zrobić za pomocą dekoratorów, jak w tym przykładzie poniżej dla TypeScript:
class YourClass {
@Singleton static singleton() {}
}
function Singleton(target, name, descriptor) {
var instance;
descriptor.value = () => {
if(!instance) instance = new target;
return instance;
};
}
Następnie używasz swojego singletona w ten sposób:
var myInstance = YourClass.singleton();
W tym piśmie dekoratory nie są łatwo dostępne w silnikach JavaScript. Musisz upewnić się, że środowisko wykonawcze JavaScript ma włączone dekoratory lub użyć kompilatorów takich jak Babel i TypeScript.
Zauważ też, że instancja singleton jest tworzona jako „leniwa”, tzn. Jest tworzona tylko przy pierwszym użyciu.
Wzór modułu: w „bardziej czytelnym stylu”. Możesz łatwo zobaczyć, które metody są publicznymi, a które prywatnymi
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");
teraz możesz korzystać z metod publicznych takich jak
module.method2 (); // -> Wywołuję metodę prywatną w ramach alertu dotyczącego metody publicznej („cześć, jestem metodą prywatną”)
Singel:
Upewnij się, że klasa ma tylko jedną instancję i zapewnij do niej globalny punkt dostępu.
Wzorzec Singleton ogranicza liczbę wystąpień określonego obiektu do tylko jednego. Ta pojedyncza instancja nazywa się singletonem.
Obiekt Singleton jest implementowany jako natychmiastowa anonimowa funkcja. Funkcja jest wykonywana natychmiast, zawijając ją w nawiasy, a następnie dwa dodatkowe nawiasy. Nazywa się to anonimowym, ponieważ nie ma nazwy.
Przykładowy program,
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()
Najprostsze / najczystsze dla mnie oznacza również po prostu zrozumienie i brak dzwonków i gwizdków, o czym wiele się mówi w wersji Java dyskusji:
Jaki jest skuteczny sposób na implementację wzorca singleton w Javie?
Odpowiedź, która najlepiej pasuje do najprostszych / najczystszych z mojego punktu widzenia, to:
https://stackoverflow.com/a/70824/1497139
I tylko częściowo można to przetłumaczyć na JavaScript. Niektóre różnice w Javascript są następujące:
Ale biorąc pod uwagę najnowszą składnię ECMA, można zbliżyć się do:
Wzór singletonu jako przykład klasy 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;
}
}
Przykładowe użycie
console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);
Przykład wyniku
DefaultField1
DefaultField2
function Once() {
return this.constructor.instance || (this.constructor.instance = this);
}
function Application(name) {
let app = Once.call(this);
app.name = name;
return app;
}
Jeśli jesteś w klasach:
class Once {
constructor() {
return this.constructor.instance || (this.constructor.instance = this);
}
}
class Application extends Once {
constructor(name) {
super();
this.name = name;
}
}
Test:
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
Jeśli chcesz korzystać z klas:
class Singleton {
constructor(name, age) {
this.name = name;
this.age = age;
if(this.constructor.instance)
return this.constructor.instance;
this.constructor.instance = this;
}
}
let x = new Singleton('s',1);
let y = new Singleton('k',2);
Dane wyjściowe dla powyższych będą:
console.log(x.name,x.age,y.name,y.age) // s 1 s 1
Kolejny sposób pisania Singletona za pomocą funkcji
function AnotherSingleton (name,age) {
this.name = name;
this.age = age;
if(this.constructor.instance)
return this.constructor.instance;
this.constructor.instance = this;
}
let a = new AnotherSingleton('s',1);
let b = new AnotherSingleton('k',2);
Dane wyjściowe dla powyższych będą:
console.log(a.name,a.age,b.name,b.age)// s 1 s 1