Javascript:最好的Singleton模式

Kaz*_*Koe 94 javascript singleton design-patterns

可能重复:
在JavaScript中实现单例的最简单/最简洁的方法?

我将这种模式用于单身人士,在单例中,单身人士是PlanetEarth:

var NAMESPACE = function () {

    var privateFunction1 = function () {
        privateFunction2();
    };

    var privateFunction2 = function () {
        alert('I\'m private!');
    };

    var Constructors = {};

    Constructors.PlanetEarth = function () {
        privateFunction1();
        privateFunction2();
    };

    Constructors.PlanetEarth.prototype = {
        someMethod: function () {
            if (console && console.log) {
                console.log('some method');             
            }
        }
    };

    Constructors.Person = function (name, address) {
        this.name = name;
        this.address = address;
    };

    Constructors.Person.prototype = {
        walk: function () {
            alert('STOMP!');
        }
    };

    return {
        Person: Constructors.Person, // there can be many
        PlanetEarth: new Constructors.PlanetEarth() // there can only be one!
    };

}();
Run Code Online (Sandbox Code Playgroud)

由于PlanetEarth的构造函数仍然是私有的,因此只能有一个.

现在,有些东西告诉我,这种自煮熟的东西不是最好的东西,主要是因为我没有接受过学术教育,而且我倾向于以愚蠢的方式解决问题.你会建议什么作为一种更好的替代方法,哪种更好被定义为风格更好和/或更强大

Tom*_*ero 159

(1)更新2019年:ES7版本

class Singleton {
    static instance;

    constructor() {
        if (instance) {
            return instance;
        }

        this.instance = this;
    }

    foo() {
        // ...
    }
}

console.log(new Singleton() === new Singleton());
Run Code Online (Sandbox Code Playgroud)

(2)ES6版本

class Singleton {
    constructor() {
        const instance = this.constructor.instance;
        if (instance) {
            return instance;
        }

        this.constructor.instance = this;
    }

    foo() {
        // ...
    }
}

console.log(new Singleton() === new Singleton());
Run Code Online (Sandbox Code Playgroud)

找到最佳解决方案:http: //code.google.com/p/jslibs/wiki/JavascriptTips#Singleton_pattern

function MySingletonClass () {

  if (arguments.callee._singletonInstance) {
    return arguments.callee._singletonInstance;
  }

  arguments.callee._singletonInstance = this;

  this.Foo = function () {
    // ...
  };
}

var a = new MySingletonClass();
var b = MySingletonClass();
console.log( a === b ); // prints: true
Run Code Online (Sandbox Code Playgroud)

对于那些想要严格版本的人:

(function (global) {
  "use strict";
  var MySingletonClass = function () {

    if (MySingletonClass.prototype._singletonInstance) {
      return MySingletonClass.prototype._singletonInstance;
    }

    MySingletonClass.prototype._singletonInstance = this;

    this.Foo = function() {
      // ...
    };
  };

var a = new MySingletonClass();
var b = MySingletonClass();
global.result = a === b;

} (window));

console.log(result);
Run Code Online (Sandbox Code Playgroud)

  • 更新了严格的版本,先生.请恢复投票. (53认同)
  • 有没有办法在不使用新的情况下做到这一点?在你的例子中,你做了一个新的Singleton,这是一种反直觉的.不应该是a = Singleton.getInstance()然后b = Singleton.getInstance()?? (6认同)
  • 如果我调用`MySingletonClass()`然后调用`new MySingletonClass()`??? 它会产生一个Window对象. (4认同)
  • 我投了这个,因为我正在寻找一个简单的哈希映射的过度解决方案的例子.:) (2认同)
  • @endavid Chrome 71尚不支持ES7静态属性。仅ES6。请参阅下一个解决方案。 (2认同)

bob*_*nce 24

为什么要为单个对象使用构造函数和原型?

以上相当于:

var earth= {
    someMethod: function () {
        if (console && console.log)
            console.log('some method');                             
    }
};
privateFunction1();
privateFunction2();

return {
    Person: Constructors.Person,
    PlanetEarth: earth
};
Run Code Online (Sandbox Code Playgroud)

  • 如果页面上包含两次,则最新对象将覆盖之前的对象.在实践中,它发生 - 有时带来意想不到的后果.单身闭合模式阻止了这一点.因此,如果您分发脚本/库,它将优雅地处理使用它的其他人的滥用.出于这个原因,Google的大多数API库都是这样做的.假设我在网站上使用谷歌地图,但想要由某些第三方安装小部件,第三方也明确包括地图库.我是否应该更改第三方代码,或者库本身是否应该优雅地处理此问题? (13认同)
  • 如果使用:var earth = earth ||,它将不会覆盖 {....}; (10认同)
  • ?你不可能做任何事来防御"攻击".如果有人将代码注入您的JS源,那么您已经完全丢失了.JavaScript不是为在原点内提供安全边界而设计的. (9认同)
  • 如果您使用正确的文件管理器(如requirejs),它也不会覆盖它. (3认同)
  • "它不会,如果"......请,任何人仍然可以通过例如在不使用闭包模式时通过bookmarklet/favlet注入javascript来覆盖单例.这不仅仅是关于您正确使用自己的代码,还涉及避免恶意攻击. (3认同)

小智 18

通过Tom 扩展上述帖子,如果您需要类类型声明并使用变量访问单例实例,下面的代码可能会有所帮助.我喜欢这种符号,因为代码很少自我引导.

function SingletonClass(){
    if ( arguments.callee.instance )
        return arguments.callee.instance;
    arguments.callee.instance = this;
}


SingletonClass.getInstance = function() {
    var singletonClass = new SingletonClass();
    return singletonClass;
};
Run Code Online (Sandbox Code Playgroud)

要访问单身人士,你会的

var singleTon = SingletonClass.getInstance();
Run Code Online (Sandbox Code Playgroud)

  • 实际上,应该尝试避免使用'callee' - 来自MDN JavaScript严格模式引用(解释为什么在严格模式下不支持被调用者) - "在普通代码中,arguments.callee引用封闭函数.这个用例很弱:简单地命名封闭函数!此外,arguments.callee实质上阻碍了内联函数之类的优化,因为如果访问arguments.callee,必须能够提供对非内联函数的引用." (6认同)