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


当前回答

我认为我已经找到了用JavaScript编程的最简洁的方法,但您需要一些想象力。我是从《JavaScript: the Good Parts》一书中的一个工作技巧中得到这个想法的。

不用new关键字,你可以这样创建一个类:

function Class()
{
    var obj = {}; // Could also be used for inheritance if you don't start with an empty object.

    var privateVar;
    obj.publicVar;

    obj.publicMethod = publicMethod;
    function publicMethod(){}

    function privateMethod(){}

    return obj;
}

你可以这样实例化上面的对象:

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

现在有了这个工作方法,你可以创建一个像这样的单例:

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

现在可以通过调用来获取实例

var obj = ClassSingleton.getInstance();

我认为这是最简洁的方法,因为完整的“类”甚至无法访问。

其他回答

如果你想使用类:

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

以上的输出将是:

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

另一种使用函数编写Singleton的方法

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

以上的输出将是:

console.log(a.name, a.age, b.name, b.age) // s 1 s 1

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

话虽如此,这里是一个使用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())

如果你正在使用node.JS,那么你可以利用node.JS的缓存机制,你的单例将像这样简单:

class Singleton {
    constructor() {
        this.message = 'I am an instance';
    }
}
module.exports = new Singleton();

请注意,我们导出的不是类Singleton,而是实例Singleton()。

Node.JS将在每次需要时缓存和重用相同的对象。

更多细节请查看:Node.JS和单例模式

我相信这是最简单/最干净和最直观的方式,尽管它需要ECMAScript 2016 (ES7):

导出默认类Singleton { 静态实例; 构造函数(){ 如果(){ 返回实例; } 这一点。State = "公爵"; 这一点。实例= this; } }

源代码来自:adam-bien.com

关键是要理解闭包背后的重要性。因此,在闭包的帮助下,即使在内部函数内部的属性也将是私有的。

var Singleton = function () {
    var instance;

    function init() {

       function privateMethod() {
           console.log("private via closure");
       }

       var privateVariable = "Private Property";

       var privateRandomNumber = Math.random(); // This is also private

       return {
           getRandomNumber: function () {  // Access via getter in init call
               return privateRandomNumber;
           }
       };
    };

    return {
        getInstance: function () {

            if (!instance) {
                instance = init();
            }
            return instance;
        }
    };
};