Simplest/Cleanest way to implement singleton in JavaScript?

后端 未结 30 1082
名媛妹妹
名媛妹妹 2020-11-22 05:17

What is the simplest/cleanest way to implement singleton pattern in JavaScript?

相关标签:
30条回答
  • 2020-11-22 05:36

    @CMS and @zzzzBov have both given wonderful answers, but just to add my own interpretation based on my having moved into heavy node.js development from PHP/Zend Framework where singleton patterns were common.

    The following, comment-documented code is based on the following requirements:

    • one and only one instance of the function object may be instantiated
    • the instance is not publicly available and may only be accessed through a public method
    • the constructor is not publicly available and may only be instantiated if there is not already an instance available
    • the declaration of the constructor must allow its prototype chain to be modified. This will allow the constructor to inherit from other prototypes, and offer "public" methods for the instance

    My code is very similar to @zzzzBov's except I've added a prototype chain to the constructor and more comments that should help those coming from PHP or a similar language translate traditional OOP to Javascripts prototypical nature. It may not be the "simplest" but I believe it is the most proper.

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

    Note that technically, the self-executing anonymous function is itself a Singleton as demonstrated nicely in the code provided by @CMS. The only catch here is that it is not possible to modify the prototype chain of the constructor when the constructor itself is anonymous.

    Keep in mind that to Javascript, the concepts of “public” and “private” do not apply as they do in PHP or Java. But we have achieved the same effect by leveraging Javascript’s rules of functional scope availability.

    0 讨论(0)
  • 2020-11-22 05:36

    can I put my 5 coins. I have a constructor function, ex.

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

    What I need to do is just every object created by this CF will be same.

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

    test

    var x1 = new X();
    var x2 = new X();
    console.log(x1 === x2)
    
    0 讨论(0)
  • 2020-11-22 05:37

    I'm not sure I agree with the module pattern being used as a replacement for a singleton pattern. I've often seen singletons used and abused in places where they're wholly unnecessary, and I'm sure the module pattern fills many gaps where programmers would otherwise use a singleton, however the module pattern is not a singleton.

    module pattern:

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

    Everything initialized in the module pattern happens when Foo is declared. Additionally, the module pattern can be used to initialize a constructor, which could then be instantiated multiple times. While the module pattern is the right tool for many jobs, it's not equivalent to a singleton.

    singleton pattern:

    short form
    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();
    }
    
    long form, using module pattern
    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 both versions of the Singleton pattern that I've provided, the constructor itself can be used as the accessor:

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

    If you don't feel comfortable using the constructor this way, you can throw an error in the if (instance) statement, and stick to using the long form:

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

    I should also mention that the singleton pattern fits well with the implicit constructor function pattern:

    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
    
    0 讨论(0)
  • 2020-11-22 05:40

    If you want to use classes:

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

    Output for the above will be:

    console.log(x.name,x.age,y.name,y.age) // s 1 s 1
    

    Another way of writing Singleton using function

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

    Output for the above will be:

    console.log(a.name,a.age,b.name,b.age)// s 1 s 1
    
    0 讨论(0)
  • 2020-11-22 05:41

    Module pattern: in "more readable style". You can see easily which methods are publics and which ones are privates

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

    now you can use publics methods like

    module.method2(); //-> I'm calling a private method over a public method alert("hi im a private method")

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

    0 讨论(0)
  • 2020-11-22 05:43
    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
    
    0 讨论(0)
提交回复
热议问题