Simplest/Cleanest way to implement singleton in JavaScript?

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

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

30条回答
  •  别那么骄傲
    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
    

提交回复
热议问题