用JavaScript实现单例模式的最简单/最干净的方法是什么?


当前回答

最明确的答案应该是Addy Osmani所著的《学习JavaScript设计模式》一书。

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 = "I'm 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; } }; })();

其他回答

最明确的答案应该是Addy Osmani所著的《学习JavaScript设计模式》一书。

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 = "I'm 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; } }; })();

所以公平地说,最简单的答案通常是最好的。一个对象字面值总是一个实例。没有什么理由去做更复杂的事情,除了按需分配内存。

话虽如此,这里是一个使用ES6的经典单例实现。

实例“field”是“private”。这实际上意味着我们将实例隐藏为构造函数的属性。某个不是构造函数的地方。原型,它将通过原型继承对实例可用。 构造函数是“private”。当调用者不是静态getInstance方法时,我们实际上只是抛出一个错误。

同样值得注意。理解这个关键词在不同语境下的含义是很重要的。

在构造函数中,this指向创建的实例。

在静态getInstance方法中,this指向dot的左边,宇宙构造函数,它是一个对象,像JS中的大多数东西一样,可以保存属性。

class Universe { constructor() { if (!((new Error).stack.indexOf("getInstance") > -1)) { throw new Error("Constructor is private. Use static method getInstance."); } this.constructor.instance = this; this.size = 1; } static getInstance() { if (this.instance) { return this.instance; } return new this; } expand() { this.size *= 2; return this.size; } } console.log(Universe.getInstance()) console.log(Universe.getInstance().expand()) console.log(Universe.getInstance()) console.log(new Universe())

您可以在每次新的执行中返回相同的实例-

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

在Node.js版本6中工作:

class Foo {
  constructor(msg) {

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

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

我们测试:

const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }
class Singelton {
    static #instance;

    #testValue;

    constructor() {
        if (Singelton.#instance instanceof Singelton) {
            return Singelton.#instance;
        }

        Singelton.#instance = this;
        return Singelton.#instance;
    }

    get testValue() {
        return this.#testValue;
    }

    set testValue(value) {
        this.#testValue = value;
    }
}

测试:

let x = new Singelton();
x.testValue = 123;

let y = new Singelton();

console.log({isSingelton: x === y, testValueFromY: y.testValue});