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


当前回答

这就是我如何使用ES6特性实现单例模式。是的,我知道这看起来不像面向对象的方法,但我发现这个方法很容易实现,而且是一种干净的实现方式。

const Singleton = (() => {
  var _instance = !_instance && new Object('Object created....');
  return () => _instance;
})();

//************************************************************************

var instance1 = Singleton();
var instance2 = Singleton();
console.log(instance1 === instance2); // true

其他回答

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

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

var singleton = (function () {

    var singleton = function(){
        // Do stuff
    }
    var instance = new singleton();
    return function(){
        return instance;
    }
})();

一个没有getInstance方法的解决方案。

我反对我的回答,看看我的另一个。

通常,模块模式(参见Christian C. Salvadó的答案)不是单例模式就足够好了。然而,单例的一个特点是它的初始化会延迟到需要对象时。模块模式缺乏这个特性。

我的命题(CoffeeScript):

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

在JavaScript中编译为:

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

然后我可以做以下事情:

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

我从JavaScript模式中得到了这个例子 用编码和设计模式构建更好的应用程序一书(Stoyan Stefanov著)。如果你需要一些简单的实现类,比如单例对象,你可以使用一个直接函数,如下所示:

var ClassName;

(function() {
    var instance;
    ClassName = function ClassName() {
        // If the private instance variable is already initialized, return a reference
        if(instance) {
            return instance;
        }
        // If the instance is not created, save a pointer of the original reference
        // to the private instance variable.
        instance = this;

        // All constructor initialization will be here
        // i.e.:
        this.someProperty = 0;
        this.someMethod = function() {
            // Some action here
        };
    };
}());

你可以通过下面的测试用例来检查这个例子:

// Extending defined class like singleton object using the new prototype property
ClassName.prototype.nothing = true;
var obj_1 = new ClassName();

// Extending the defined class like a singleton object using the new prototype property
ClassName.prototype.everything = true;
var obj_2 = new ClassName();

// Testing makes these two objects point to the same instance
console.log(obj_1 === obj_2); // Result is true, and it points to the same instance object

// All prototype properties 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 are defined inside of the constructor
console.log(obj_1.someProperty); // Outputs 0
console.log(obj_2.someProperty); // Outputs 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

这种方法通过了所有测试用例,而当使用原型扩展时,私有静态实现将失败(它可以被修复,但并不简单),而公共静态实现则不太可取,因为实例是公开给公众的。

jsFiddly demo.

我发现下面是最简单的单例模式,因为使用new操作符可以立即在函数中使用它,消除了返回对象字面量的需要:

Var singleton = new(函数(){ var private = "一个私有值"; 这一点。printSomething = function() { console.log(私人); } }) (); singleton.printSomething ();