Javascript:最佳单例模式
Posted
技术标签:
【中文标题】Javascript:最佳单例模式【英文标题】:Javascript: best Singleton pattern [duplicate] 【发布时间】:2010-12-10 18:49:48 【问题描述】:可能重复:Simplest/Cleanest way to implement singleton in 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 的构造函数是私有的,所以只能有一个。
现在,有件事告诉我,这种自制的东西并不是最好的,主要是因为我没有受过学术教育,而且我倾向于以愚蠢的方式解决问题。您会提出什么作为我的方法的更好替代方法,其中更好被定义为风格上更好和/或更强大?
【问题讨论】:
【参考方案1】:(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);
【讨论】:
已更新为严格版本,先生。请撤销投票。 我投了赞成票,因为我正在寻找一个简单哈希映射的过度烘焙解决方案的示例。 :) 有没有办法在不使用 new 的情况下做到这一点?在您的示例中,您执行了 = new Singleton,这有点违反直觉。不应该是 a = Singleton.getInstance() 然后 b= Singleton.getInstance() 吗?? 如果我打电话给MySingletonClass()
然后new MySingletonClass()
怎么办???它将产生一个 Window 对象。
@endavid Chrome 71 还不支持 ES7 静态属性。只有 ES6。请参阅下一个解决方案。【参考方案2】:
Extending 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,则必须提供对未内联函数的引用。 【参考方案3】: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"]
【讨论】:
单例的意义不是你没有明确地实例化它,而是(a)只有一个实例(这就是为什么它被称为单例)和(b)它是自动声明的在全局命名空间中?在我看来,Lecleuse 先生的模式是针对“类”而不是单例的。 这段代码实际上是相当危险的误导。getInstance
函数内部的this
实际上是指全局对象(浏览器中的window
)。基本上,singletonInstance
会泄漏到全局范围内——如果你有不止一个使用名称 singletonInstance
的类,那么祝你好运。在严格模式下,你会得到TypeError: this is undefined
,这是正确的!【参考方案4】:
为什么要为单个对象使用构造函数和原型设计?
以上等价于:
var earth=
someMethod: function ()
if (console && console.log)
console.log('some method');
;
privateFunction1();
privateFunction2();
return
Person: Constructors.Person,
PlanetEarth: earth
;
【讨论】:
如果在一个页面中包含两次,最新的对象将覆盖较早的对象。在实践中,它会发生——有时会带来意想不到的后果。单例闭包模式可以防止这种情况。因此,如果您分发脚本/库,它将优雅地处理使用它的其他人的滥用。出于这个原因,大多数 Google 的 API 库都是这样做的。假设我在一个网站上使用谷歌地图,但想安装一些第三方的小部件,其中也明确包含了地图库。我应该更改第三方代码,还是应该由库本身优雅地处理这个? 如果你使用它不会覆盖:var earth = earth || .... ; 如果你使用合适的文件管理器,比如 requirejs,它也不会覆盖它。 “它不会”...拜托,任何人仍然可以通过例如覆盖单例在不使用闭包模式时通过小书签/favlet 注入 javascript。这不仅关乎您正确使用自己的代码,还关乎避免恶意攻击。 ?你不可能做任何事情来防御“攻击”。如果有人将代码注入到您的 JS 源中,您已经完全迷失了。 JavaScript 的设计初衷不是为了在源内提供安全边界。以上是关于Javascript:最佳单例模式的主要内容,如果未能解决你的问题,请参考以下文章