it-swarm.com.de

Einfachste/sauberste Methode zur Implementierung von Singleton in JavaScript?

Was ist der einfachste/sauberste Weg, um Singleton-Pattern in JavaScript zu implementieren?

264
Jakub Arnold

Ich denke, der einfachste Weg ist, ein einfaches Objekt-Literal zu deklarieren:

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

Wenn Sie private Mitglieder in Ihrer Singleton-Instanz haben möchten, können Sie Folgendes tun:

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

  function privateMethod () {
    // ...
  }

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

Dies wurde als the module pattern bezeichnet. Sie können damit grundsätzlich private Member auf einem Objekt kapseln, indem Sie die Verwendung von closures nutzen.

293
CMS

Ich denke der sauberste Ansatz ist so etwas wie:

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;
        }
   };
})();

Anschließend können Sie die Funktion als aufrufen

var test = SingletonFactory.getInstance();
157
sebarmeli

Ich bin nicht sicher, ob ich mit dem Modulmuster einverstanden bin, das als Ersatz für ein Singleton-Muster verwendet wird. Ich habe oft gesehen, wie Singletons an Orten verwendet und missbraucht wurden, an denen sie völlig unnötig sind, und ich bin sicher, dass das Modulmuster viele Lücken füllt, in denen Programmierer sonst ein Singleton verwenden würden. Das Modulmuster ist jedoch nicht a Singleton.

modul muster:

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

Alles, was im Modulmuster initialisiert wurde, geschieht, wenn Foo deklariert wird. Darüber hinaus kann das Modulmuster zum Initialisieren eines Konstruktors verwendet werden, der dann mehrmals instanziiert werden kann. Während das Modulmuster für viele Jobs das richtige Werkzeug ist, entspricht es nicht einem Singleton.

singleton-Pattern:

kurzform
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();
}
lange Form mit Modulmuster
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;
}());

In beiden Versionen des von mir bereitgestellten Singleton-Musters kann der Konstruktor selbst als Accessor verwendet werden:

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

Wenn Sie mit dem Konstruktor auf diese Weise nicht zufrieden sind, können Sie einen Fehler in der if (instance)-Anweisung ausgeben und das lange Formular verwenden:

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

Ich sollte auch erwähnen, dass das Singleton-Muster gut zum impliziten Konstruktorfunktionsmuster passt:

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

Im 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
13
Xaqron

Es gibt mehr als eine Möglichkeit, eine Katze zu häuten :) Je nach Ihrem Geschmack oder besonderen Bedürfnissen können Sie eine der vorgeschlagenen Lösungen anwenden. Ich persönlich besuche die erste Lösung von CMS, wann immer dies möglich ist (wenn Sie keine Privatsphäre benötigen). Da es um die einfachste und sauberste Frage ging, ist dies der Gewinner. Oder auch:

var myInstance = {}; // done!

Dies (Zitat aus meinem Blog) ...

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

es macht nicht viel Sinn (mein Blog-Beispiel tut es auch nicht), weil es keine privaten Variablen benötigt, also ist es so ziemlich das Gleiche wie:

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

Ich lehne meine Antwort ab, siehe meine andere .

Normalerweise ist das Modul-Pattern (siehe Antwort des CMS), das NICHT Singleton-Pattern ist, gut genug. Eines der Merkmale von Singleton ist jedoch, dass seine Initialisierung verzögert wird, bis ein Objekt benötigt wird. Modulmuster fehlt diese Funktion.

Mein Vorschlag (CoffeeScript):

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

Was dazu in JavaScript kompiliert wurde:

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

Dann kann ich folgendes machen:

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

Ich habe dieses Beispiel aus JavaScript PatternsBuild bessere Anwendungen mit Coding and Design PatternsBy von Stoyan Stefanov für den Fall, dass Sie eine einfache Implementierungsklasse wie Singletone-Objekt benötigen, können Sie die sofortige Funktion wie folgt verwenden:

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
        };
    };
}());

Sie können dieses Beispiel anhand des folgenden Testfalls überprüfen:

//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 

Dieser Ansatz besteht alle Testfälle, während die private statische Implementierung fehlschlägt, wenn eine Prototyperweiterung verwendet wird (dies kann zwar behoben werden, ist aber nicht einfach), und die öffentliche statische Implementierung ist weniger empfehlenswert, da die Instanz der Öffentlichkeit zugänglich gemacht wird.

jsFleißige Demo.

6
Khamidulla

Kurze Antwort:

Da JavaScript nicht blockierend ist, werden Singletons in JavaScript sehr hässlich verwendet. Globale Variablen geben Ihnen auch in der gesamten Anwendung eine Instanz ohne all diese Rückrufe. Das Modulmuster verbirgt sanft die Interna hinter der Schnittstelle. Siehe @CMS-Antwort.

Aber da du ein Singleton haben wolltest ...

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);
    }
  };

};

Verwendungszweck:

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();
});

Erläuterung:

Singletons geben Ihnen durch die gesamte Anwendung mehr als nur eine Instanz: Ihre Initialisierung wird bis zur ersten Verwendung verzögert. Das ist wirklich eine große Sache, wenn Sie sich mit Objekten beschäftigen, deren Initialisierung teuer ist. Teuer bedeutet in der Regel E/A und in JavaScript E/A immer Rückrufe.

Vertrauen Sie nicht auf Antworten, die Ihnen eine Schnittstelle wie instance = singleton.getInstance() geben, sie verfehlen alle den Punkt.

Wenn Callback nicht ausgeführt wird, wenn die Instanz bereit ist, funktionieren sie nicht, wenn der Initialisierer E/A ausführt. 

Ja, Rückrufe sehen immer hässlicher aus als ein Funktionsaufruf, der sofort die Objektinstanz zurückgibt. Aber nochmal: Wenn Sie E/A ausführen, sind Rückrufe obligatorisch. Wenn Sie keine I/O-Vorgänge ausführen möchten, ist die Instantiierung billig genug, um sie beim Programmstart auszuführen.

Beispiel 1, billiger Initialisierer:

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);
});

Beispiel 2, Initialisierung mit I/O:

In diesem Beispiel fälscht setTimeout einige teure E/A-Vorgänge. Dies zeigt, warum Singletons in JavaScript wirklich Rückrufe benötigen.

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

Ich denke, ich habe den saubersten Weg gefunden, in JavaScript zu programmieren, aber Sie brauchen etwas Phantasie. Diese Idee bekam ich aus einer Arbeitstechnik im Buch "Javascript die guten Teile".

Anstelle des neuen Schlüsselworts können Sie eine Klasse wie folgt erstellen:

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;
}

Sie können das obige Objekt instanziieren, indem Sie sagen:

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

Nun können Sie mit dieser Arbeitsmethode ein Singleton wie folgt erstellen:

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 };

}();

Jetzt können Sie Ihre Instanz erhalten, indem Sie anrufen

var obj = ClassSingleton.getInstance();

Ich denke, das ist der schönste Weg, da die komplette "Klasse" nicht einmal zugänglich ist. 

5
David

Die klarste Antwort sollte diese aus dem Buch Learning JavaScript Design Patterns von Addy Osmani sein.

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 und @zzzzBov haben beide wundervolle Antworten gegeben, aber nur um meine eigene Interpretation hinzuzufügen, basierend auf meiner Entwicklung in knoten node.js von PHP/Zend Framework, wo Singleton-Patterns üblich waren.

Der folgende, mit Kommentaren dokumentierte Code basiert auf den folgenden Anforderungen:

  • es kann nur eine Instanz des Funktionsobjekts instanziiert werden
  • die Instanz ist nicht öffentlich verfügbar und kann nur über eine öffentliche Methode aufgerufen werden
  • der Konstruktor ist nicht öffentlich verfügbar und kann nur dann instanziiert werden, wenn noch keine Instanz verfügbar ist
  • die Deklaration des Konstruktors muss die Änderung der Prototypkette ermöglichen. Dadurch kann der Konstruktor von anderen Prototypen erben und "öffentliche" Methoden für die Instanz anbieten

Mein Code ist @ zzzzBov sehr ähnlich, mit der Ausnahme, dass ich dem Konstruktor eine Prototypkette und weitere Kommentare hinzugefügt habe, die denjenigen helfen sollen, die aus PHP oder einer ähnlichen Sprache stammen, um traditionelle OOP in Javascripts-Prototyp zu übersetzen. Es ist vielleicht nicht das "einfachste", aber ich glaube, dass es das Richtigste ist.

// 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'

Beachten Sie, dass die selbstausführende anonyme Funktion selbst ein Singleton ist, wie der Code von @CMS zeigt. Der einzige Haken dabei ist, dass es nicht möglich ist, die Prototypkette des Konstruktors zu ändern, wenn der Konstruktor selbst anonym ist.

Beachten Sie, dass für Javascript die Begriffe "öffentlich" und "privat" nicht wie in PHP oder Java gelten. Den gleichen Effekt haben wir jedoch erzielt, indem wir die Javascript-Regeln zur Verfügbarkeit des Funktionsumfangs nutzen.

4
talentedmrjones

Nicht sicher, warum niemand dies angesprochen hat, aber Sie könnten es einfach tun:

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

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

kann ich meine 5 Münzen legen? Ich habe eine Konstruktorfunktion, z. 

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

Was ich tun muss, ist, dass jedes von dieser CF erstellte Objekt gleich ist.

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

prüfung

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

Folgendes funktioniert im Knoten v6

class Foo {
  constructor(msg) {

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

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

Wir testen:

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

Hier ist das einfache Beispiel, um Singleton-Muster in Java-Skript zu erklären.

 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

Ich habe folgendes für das einfachste Singleton-Muster gefunden, weil die Verwendung des new -Operators this innerhalb der Funktion sofort verfügbar ist, sodass kein Objektliteral zurückgegeben werden muss:

var singleton = new (function () {

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

singleton.printSomething();

2
Mark

Sie können dies mit Dekorateuren wie in diesem Beispiel für TypeScript tun:

class YourClass {

    @Singleton static singleton() {}

}

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

Dann benutzen Sie Ihr Singleton so:

var myInstance = YourClass.singleton();

Zum jetzigen Zeitpunkt sind Dekoratoren in JavaScript-Engines nicht ohne weiteres verfügbar. Sie müssen sicherstellen, dass in Ihrer JavaScript-Laufzeit Dekorierer tatsächlich aktiviert sind oder Compiler wie Babel und TypeScript verwenden.

Beachten Sie auch, dass die Singleton-Instanz "faul" erstellt wird, d. H. Sie wird nur erstellt, wenn Sie sie zum ersten Mal verwenden.

1
Vad

im Folgenden finden Sie den Ausschnitt aus meinem Durchlauf zum Implementieren eines Singleton-Musters. Dies fiel mir während eines Interviewprozesses ein und ich hatte das Gefühl, dass ich das irgendwo festhalten sollte.

/*************************************************
   *     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
  *******************************************************************/

das gleiche kann auf meiner Gist Seite gefunden werden

1
curioussam

Ich brauchte mehrere Singletons mit:

  • faule Initialisierung
  • anfangsparameter

und so kam es mir so vor:

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 muss Array sein, damit dies funktioniert. Wenn Sie leere Variablen haben, geben Sie einfach in [] ein.

  • Ich habe ein Fensterobjekt in der Funktion verwendet, aber ich hätte einen Parameter übergeben können, um meinen eigenen Bereich zu erstellen

  • name- und construct-Parameter sind nur ein String für window [], aber mit einiger einfacher Typüberprüfung sind auch window.name und window.construct möglich.

1
fred

Was ist daran falsch?

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

Wie wäre es auf diese Weise, versichere einfach, dass die Klasse nicht wieder neu sein kann.

Auf diese Weise können Sie die instanceof -Op verwenden. Sie können auch die Prototypkette verwenden, um die Klasse zu erben. Es handelt sich um eine reguläre Klasse, sie kann jedoch nicht neu erstellt werden. Wenn Sie die Instanz erhalten möchten, verwenden Sie einfach 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();

Wenn Sie das Member instance nicht verfügbar machen möchten, schließen Sie es einfach ab.

1
wener

Singleton:

Stellen Sie sicher, dass eine Klasse nur eine Instanz hat, und stellen Sie einen globalen Zugriffspunkt zur Verfügung.

Das Singleton-Muster begrenzt die Anzahl der Instanzen eines bestimmten Objekts auf nur eine. Diese einzelne Instanz wird Singleton genannt.

  • Definiert getInstance (), das die eindeutige Instanz zurückgibt.
  • verantwortlich für das Erstellen und Verwalten des Instanzobjekts.

Das Singleton-Objekt wird als unmittelbar anonyme Funktion implementiert. Die Funktion wird sofort ausgeführt, indem sie in Klammern gefolgt von zwei zusätzlichen Klammern eingeschlossen wird. Es heißt anonym, weil es keinen Namen hat.

Beispielprogramm

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()

Modulmuster: in "lesbarerem Stil". Sie können leicht erkennen, welche Methoden öffentlich und welche privat sind

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");

jetzt können Sie Publics-Methoden wie verwenden

module.method2 (); // -> Ich rufe eine private Methode über einen öffentlichen Methodenalarm an ("hi im a private method")

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

1
ncubica

Ist das nicht auch ein Einzelgänger?

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

Ich benutze gerne eine Kombination des Singleton mit dem Modulmuster, die init-time-Verzweigung mit einer globalen NS - Prüfung, die in einen Abschluss eingeschlossen ist. In einem Fall, in dem sich die Umgebung nach der Initialisierung des Singleton nicht ändert; Die Verwendung eines sofort aufgerufenen Objekt-Literal zum Zurückgeben eines Moduls mit Dienstprogrammen, die einige Zeit bestehen bleiben, sollte in Ordnung sein. Ich übergebe keine Abhängigkeiten, sondern rufe nur die Singletons in ihrer eigenen kleinen Welt auf - das einzige Ziel ist: Erstellen eines Dienstprogrammmoduls zum Binden/Entbinden von Ereignissen.

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

Ich glaube, dies ist der einfachste/sauberste und intuitivste Weg, obwohl ES7 benötigt wird:

export default class Singleton {

  static instance;

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

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

}

Der Quellcode stammt von: adam-bien.com

0
Alt Eisen

Singleton in Javascript wird mit Modulmuster und -verschlüssen erreicht. Unten ist der Code, der ziemlich selbsterklärend ist - 

// 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

Sie haben nicht "im Browser" gesagt. Ansonsten können Sie NodeJS-Module verwenden. Diese sind für jeden require-Aufruf gleich. Grundbeispiel:

Der Inhalt von foo.js:

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

Der Inhalt von circle.js:

const PI = Math.PI;

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

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

Beachten Sie, dass Sie nicht auf circle.PI zugreifen können, da er nicht exportiert wird.

Während dies im Browser nicht funktioniert, ist es einfach und sauber.

0
serv-inc

Einfachstes/Sauberstes bedeutet für mich auch einfach zu verstehen und ohne Schnickschnack, wie es in der Java -Version der Diskussion viel diskutiert wird:

Was ist eine effiziente Möglichkeit, ein Singleton-Muster in Java zu implementieren?

Die Antwort, die aus meiner Sicht am einfachsten/saubersten dort passen würde, ist:

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

Und es kann nur teilweise in JavaScript übersetzt werden. Einige der Unterschiede in Javascript sind:

  • konstrukteure können nicht privat sein
  • Klassen können keine Felder deklariert haben

Angesichts der neuesten ECMA-Syntax ist es jedoch möglich, folgende Punkte näher zu betrachten:

Singleton-Muster als JavaScript-Klassenbeispiel

 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;
  }
}

Beispielverwendung

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

Beispiel Ergebnis

DefaultField1
DefaultField2
0
Wolfgang Fahl

Hauptschlüssel ist die Bedeutung von Undertand Closure dahinter. So wird auch innerhalb der inneren Funktion mit Hilfe von Closure die Eigenschaft privat. 

var Singleton = Funktion () { var Instanz;

 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;
}

Wenn Sie in Klassen sind:

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

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

        this.name = name;
    }
}

Prüfung:

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

Sie können dieselbe Instanz in jeder Ausführung von new zurückgeben. 

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