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


当前回答

这应该可以工作:

function Klass() {
   var instance = this;
   Klass = function () { return instance; }
}

其他回答

function Once() {
    return this.constructor.instance || (this.constructor.instance = this);
}

function Application(name) {
    let app = Once.call(this);

    app.name = name;

    return app;
}

如果你在上课:

class Once {
    constructor() {
        return this.constructor.instance || (this.constructor.instance = this);
    }
}

class Application extends Once {
    constructor(name) {
        super();

        this.name = name;
    }
}

测试:

console.log(new Once() === new Once());

let app1 = new Application('Foobar');
let app2 = new Application('Barfoo');

console.log(app1 === app2);
console.log(app1.name); // Barfoo

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

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

在ES6中正确的方法是:

MyClass { 构造函数(){ if (MyClass._instance) { 抛出新的错误("单例类不能实例化超过一次。") } MyClass。_instance = this; / /……其余的构造函数代码在此之后 } } var instanceOne = new MyClass() //执行成功 var instanceTwo = new MyClass() //抛出错误

或者,如果你不想在创建第二个实例时抛出错误,你可以只返回最后一个实例,如下所示:

MyClass { 构造函数(){ if (MyClass._instance) { 返回MyClass._instance } MyClass。_instance = this; / /……其余的构造函数代码在此之后 } } var instanceOne = new MyClass() var instanceTwo = new MyClass() console.log(instanceOne === instanceTwo) //日志为true

我喜欢将单例模式和模块模式结合起来使用,并将初始化时分支与Global NS检查结合起来使用,并将它们包装在一个闭包中。

在初始化单例后环境不会改变的情况下,使用立即调用的object-literal来返回一个充满实用程序的模块,该模块将持续一段时间。

我没有传递任何依赖项,只是在它们自己的小世界中调用单例对象——唯一的目标是:为事件绑定/解绑定创建一个实用程序模块(设备方向/方向变化也可以在这种情况下工作)。

window.onload = ( function( _w ) {
    console.log.apply( console, ['it', 'is', 'on'] );
    ( {
        globalNS : function() {
            var nameSpaces = ["utils", "eventUtils"],
                nsLength = nameSpaces.length,
                possibleNS = null;

            outerLoop:
            for ( var i = 0; i < nsLength; i++ ) {
                if ( !window[nameSpaces[i]] ) {
                    window[nameSpaces[i]] = this.utils;
                    break outerLoop;
                };
            };
        },
        utils : {
            addListener : null,
            removeListener : null
        },
        listenerTypes : {
            addEvent : function( el, type, fn ) {
                el.addEventListener( type, fn, false );
            },
            removeEvent : function( el, type, fn ) {
                el.removeEventListener( type, fn, false );
            },
            attachEvent : function( el, type, fn ) {
                el.attachEvent( 'on'+type, fn );
            },
            detatchEvent : function( el, type, fn ) {
                el.detachEvent( 'on'+type, fn );
            }
        },
        buildUtils : function() {
            if ( typeof window.addEventListener === 'function' ) {
                this.utils.addListener = this.listenerTypes.addEvent;
                this.utils.removeListener = this.listenerTypes.removeEvent;
            } else {
                this.utils.attachEvent = this.listenerTypes.attachEvent;
                this.utils.removeListener = this.listenerTypes.detatchEvent;
            };
            this.globalNS();
        },
        init : function() {
            this.buildUtils();
        }
    } ).init();
} ( window ) );

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

通常,模块模式(参见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