Javascript:最佳单例模式

IT技术 javascript singleton design-patterns
2021-03-12 22:28:55

可能的重复:
在 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!
    };

}();

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

现在,有些事情告诉我,这种自制的东西不是最好的,主要是因为我没有受过学术教育,而且我倾向于以愚蠢的方式解决问题。你会提出什么作为我的方法更好的替代方案,其中更好的定义是在风格上更好和/或更强大

4个回答

(1) 2019 年更新:ES7 版本

class Singleton {
    static instance;

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

        this.instance = this;
    }

    foo() {
        // ...
    }
}

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

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

找到的最佳解决方案: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

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

(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);
如果我打电话MySingletonClass()然后呢new MySingletonClass()???它将产生一个 Window 对象。
2021-04-16 22:28:55
我投了这个票,因为我正在寻找一个简单哈希映射的过度烘焙解决方案的例子。:)
2021-04-26 22:28:55
有没有办法在不使用 new 的情况下做到这一点?在您的示例中,您执行了 a = new Singleton,这有点违反直觉。不应该像 a = Singleton.getInstance() 然后 b= Singleton.getInstance() 之类的吗??
2021-04-30 22:28:55
@endavid Chrome 71 尚不支持 ES7 静态属性。只有 ES6。请参阅下一个解决方案。
2021-05-08 22:28:55
更新了严格的版本,先生。请撤回投票。
2021-05-11 22:28:55

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

以上等价于:

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

return {
    Person: Constructors.Person,
    PlanetEarth: earth
};
如果你使用它不会覆盖:var earth = earth || { .... };
2021-04-22 22:28:55
? 你不可能做任何事情来防御“攻击”。如果有人在你的 JS 源中注入了代码,你已经完全迷失了。JavaScript 并非旨在提供源内的安全边界。
2021-05-01 22:28:55
“它不会如果”...拜托,任何人仍然可以通过例如在不使用闭包模式时通过书签/favlet 注入 javascript 来覆盖单例。这不仅关乎您正确使用自己的代码,还关乎避免恶意攻击。
2021-05-03 22:28:55
如果您使用适当的文件管理器,例如 requirejs,它也不会覆盖它。
2021-05-05 22:28:55
如果这在页面上包含两次,则最新的对象将覆盖较早的对象。在实践中,它会发生 - 有时会产生意想不到的后果。单例闭包模式可以防止这种情况。因此,如果您分发一个脚本/库,它将优雅地处理使用它的其他人的误用。出于这个原因,大多数 Google 的 API 库都是这样做的。假设我在网站上使用 Google 地图,但想安装某个第三方的小部件,其中还明确包含了地图库。我应该更改第三方代码,还是库本身应该优雅地处理这个问题?
2021-05-08 22:28:55

扩展Tom 的上述帖子,如果您需要类类型声明并使用变量访问单例实例,下面的代码可能会有所帮助。我喜欢这种表示法,因为代码几乎没有自我指导。

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


SingletonClass.getInstance = function() {
    var singletonClass = new SingletonClass();
    return singletonClass;
};

要访问单身人士,您将

var singleTon = SingletonClass.getInstance();
真的,应该尽量避免使用“被调用者”——来自 MDN JavaScript 严格模式参考(解释为什么严格模式不支持被调用者)——“在正常代码中,被调用者指的是封闭函数。这个用例很弱:只需命名封闭函数!此外,arguments.callee 会大大阻碍优化,如内联函数,因为如果访问 arguments.callee,必须能够提供对未内联函数的引用。”
2021-04-29 22:28:55
function SingletonClass() 
{
    // demo variable
    var names = [];

    // instance of the singleton
    this.singletonInstance = null;

    // Get the instance of the SingletonClass
    // If there is no instance in this.singletonInstance, instanciate one
    var getInstance = function() {
        if (!this.singletonInstance) {
            // create a instance
            this.singletonInstance = createInstance();
        }

        // return the instance of the singletonClass
        return this.singletonInstance;
    }

    // function for the creation of the SingletonClass class
    var createInstance = function() {

        // public methodes
        return {
            add : function(name) {
                names.push(name);
            },
            names : function() {
                return names;
            }
        }
    }

    // wen constructed the getInstance is automaticly called and return the SingletonClass instance 
    return getInstance();
}

var obj1 = new SingletonClass();
obj1.add("Jim");
console.log(obj1.names());
// prints: ["Jim"]

var obj2 = new SingletonClass();
obj2.add("Ralph");
console.log(obj1.names());
// Ralph is added to the singleton instance and there for also acceseble by obj1
// prints: ["Jim", "Ralph"]
console.log(obj2.names());
// prints: ["Jim", "Ralph"]

obj1.add("Bart");
console.log(obj2.names());
// prints: ["Jim", "Ralph", "Bart"]
这段代码实际上是相当危险的误导。this里面的getInstance功能实际上指的是全局对象(window在浏览器中)。基本上,singletonInstance泄漏到全局范围内——如果你有不止一个这样的类使用 name ,那么祝你好运singletonInstance在严格模式下,你会得到TypeError: this is undefined,这是正确的!
2021-04-19 22:28:55
单例的重点不是您没有显式实例化它,有(a)只有一个实例(这就是为什么它被称为 SINGLEton)并且(b)它是在全局命名空间中自动声明的?在我看来,Lecleuse 先生的模式是针对“class”而不是单身人士。
2021-04-28 22:28:55