#1 楼
我认为最简单的方法是声明一个简单的对象常量:var myInstance = {
method1: function () {
// ...
},
method2: function () {
// ...
}
};
如果要在单例实例上添加私有成员,可以执行以下操作:
var myInstance = (function() {
var privateVar = '';
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// All private members are accessible here
},
publicMethod2: function () {
}
};
})();
被称为模块模式,它基本上允许您利用闭包的使用将私有成员封装在对象上。
如果要防止对单例对象的修改,可以使用ES5
Object.freeze
方法。这将使对象不可变,从而防止对其结构和值进行任何修改。
如果您使用的是ES6,则可以很容易地使用ES模块表示一个单例对象,并且可以甚至可以通过在模块作用域内声明变量来保持私有状态:
// my-singleton.js
const somePrivateState = []
function privateFn () {
// ...
}
export default {
method1() {
// ...
},
method2() {
// ...
}
}
然后您可以简单地导入单例对象以使用它:
import myInstance from './my-singleton.js'
// ...
评论
+1在具有全局变量的语言中寻找“ Singleton模式”不是很奇怪吗???
–维克多
09年10月28日在9:18
使用模块模式,公共成员将如何访问另一个公共成员?即,publicMethod1将如何调用publicMethod2?
– typeof
11年4月26日在21:50
@Tom,是的,该模式诞生于基于类的OOP语言-我记得很多实现都涉及静态getInstance方法和私有构造函数-但是IMO,这是构建单例的最“简单”方式Javascript中的对象,最后达到了相同的目的-单个对象,您无法再次初始化(没有构造函数,它只是一个对象)-。关于链接的代码,它存在一些问题,交换a和b变量声明并测试a ===窗口。干杯。
–基督徒C.Salvadó
2011年7月18日在15:40
@Victor –以这种语言查找“单例模式”并不奇怪。许多面向对象的语言都使用全局变量,并且仍在使用单例。单例不仅保证给定类只有一个对象。 Singleton具有更多功能:1)应该在首次使用时进行初始化(这不仅意味着延迟初始化,而且还确保对象确实可以使用)2)它应该是线程安全的。模块模式可以代替单例模式,但只能在浏览器中(并非总是如此)。
–skalee
11-11-3在10:03
这不应是公认的答案。这根本不是单身人士!这只是一个全局变量。两者之间存在天壤之别。
– mlibby
13年2月25日在12:52
#2 楼
我认为最干净的方法是:var SingletonFactory = (function(){
function SingletonClass() {
//do stuff
}
var instance;
return {
getInstance: function(){
if (instance == null) {
instance = new SingletonClass();
// Hide the constructor so the returned object can't be new'd...
instance.constructor = null;
}
return instance;
}
};
})();
之后,您可以将函数调用为
var test = SingletonFactory.getInstance();
评论
备注:可以使用delete instance.constructor再次读取原始构造函数。x = SingletonClass.getInstance();删除x.constructor; new x.constructor;
– Rob W
2012年12月12日下午13:42
var test = SingletonClass.getInstance()-看起来不太干净或类似JS。其他以a = new Foo()结尾的灵魂; b =新的Foo(); a === b //是
–马特西亚斯
2013年11月7日13:24
整个“ getInstance”部分对我来说更像工厂。
– Lajos Meszaros
2015年5月5日14:06
这不是单例,因为您可以使用Object.create创建它的多个实例。
– AndroidDev
17年1月13日,0:28
小提琴坏了
– HoffZ
18年2月16日在13:37
#3 楼
我不确定我是否同意将模块模式用作单例模式的替代品。我经常看到在完全不需要的地方使用和滥用单例,并且我敢肯定,模块模式会填补程序员在其他情况下会使用单例的空白。但是,模块模式不是单例。模块模式:
var foo = (function () {
"use strict";
function aPrivateFunction() {}
return { aPublicFunction: function () {...}, ... };
}());
声明
Foo
时,会发生在模块模式中初始化的所有事情。此外,模块模式可用于初始化构造函数,然后可以多次实例化该构造函数。虽然模块模式是许多作业的正确工具,但它并不等同于单例。单例模式:
短格式
var Foo = function () {
"use strict";
if (Foo._instance) {
// This allows the constructor to be called multiple times
// and refer to the same instance. Another option is to
// throw an error.
return Foo._instance;
}
Foo._instance = this;
// Foo initialization code
};
Foo.getInstance = function () {
"use strict";
return Foo._instance || new Foo();
}
长格式,使用模块模式
var Foo = (function () {
"use strict";
var instance; //prevent modification of "instance" variable
function Singleton() {
if (instance) {
return instance;
}
instance = this;
//Singleton initialization code
}
// Instance accessor
Singleton.getInstance = function () {
return instance || new Singleton();
}
return Singleton;
}());
我提供的单例模式版本,构造函数本身可以用作访问器:
var a,
b;
a = new Foo(); // Constructor initialization happens here
b = new Foo();
console.log(a === b); //true
如果您不习惯以这种方式使用构造函数,则可以在
if (instance)
语句,并坚持使用长格式:var a,
b;
a = Foo.getInstance(); // Constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); // true
我还应该提到单例模式非常适合隐式构造函数模式:
评论
我从没说过关于单例是一个坏主意还是好主意。我说过,单例的实现要复杂得多,因为您将Java的局限性与该模式混淆了,就好像根本不了解它一样。这就像通过仅在Javascript中使用匿名函数来构造构造函数和方法来实现策略模式一样。
– Esailija
13年11月17日在11:25
@Esailija,对我来说听起来像您不了解单例模式。单例模式是一种设计模式,用于将类的实例化限制为一个对象。 var singleton = {}不符合该定义。
–zzzzBov
13年11月17日在18:03
由于其局限性,这仅适用于Java之类的语言。 var singleton = {}是如何在Javascript中实现单例。
– Esailija
13年11月17日在18:14
@Esailija,“在基于原型的编程语言中,使用对象而不使用类...” JavaScript具有类的概念,因此不适用。
–zzzzBov
13年11月17日在19:22
顺便说说。 Singleton是一种反模式,无论如何也绝不能在托管沙盒环境(如JavaScript)中使用它。 misko.hevery.com/2008/08/17/singletons-are-pathologic-liars-youtube.com/watch?v=G32acYVd9LY blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx -jalf.dk/blog/2010/03/…-kore-nordmann.de/blog/0103_static_considered_harmful.html-phparch.com/2010/03/static-methods-vs-singletons-choose-noth
–本杰明·格伦鲍姆(Benjamin Gruenbaum)
13年11月17日在19:35
#4 楼
在ES6中,正确的方法是: class MyClass {
constructor() {
if (MyClass._instance) {
throw new Error("Singleton classes can't be instantiated more than once.")
}
MyClass._instance = this;
// ... Your rest of the constructor code goes after this
}
}
var instanceOne = new MyClass() // Executes succesfully
var instanceTwo = new MyClass() // Throws error
或者,如果您不希望在创建第二个实例时引发错误,则可以只返回最后一个实例,如下所示:
class MyClass {
constructor() {
if (MyClass._instance) {
return MyClass._instance
}
MyClass._instance = this;
// ... Your rest of the constructor code goes after this
}
}
var instanceOne = new MyClass()
var instanceTwo = new MyClass()
console.log(instanceOne === instanceTwo) // Logs "true"
评论
嗨,您能帮我知道_instance和instance之间的区别,因为我正在使用实例并且代码无法正常工作
– Abhinav bhardwaj
2月13日下午7:54
实例和_instance没有技术上的区别。这只是编程语言中的命名约定,我们用下划线命名私有变量。我怀疑您的代码无法正常工作的原因是您使用的是this.instance而不是MyClass.instance
– UtkarshPramodGupta
2月13日8:17
这可以通过使用将保存实例的静态私有变量来改进,例如静态#instance = null;。否则,只需修改_instance属性(将其设置为null)即可创建第二个实例。
–akinuri
12月4日8:35
#5 楼
在ECMAScript 2015(ES6)中:class Singleton {
constructor () {
if (!Singleton.instance) {
Singleton.instance = this
}
// Initialize object
return Singleton.instance
}
// Properties & Methods
}
const instance = new Singleton()
Object.freeze(instance)
export default instance
评论
如果Singleton是其他类的包装并且仅包含实例字段,则冻结是有意义的。到目前为止,此类(实例已设置为该类)可能还会包含其他字段,并且冻结对imo没有意义。
–thisismydesign
19年5月14日在15:07
#6 楼
以下在Node.js版本6中起作用:class Foo {
constructor(msg) {
if (Foo.singleton) {
return Foo.singleton;
}
this.msg = msg;
Foo.singleton = this;
return Foo.singleton;
}
}
我们测试:
const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }
#7 楼
剥皮猫的方法不止一种:)根据您的口味或特定需求,您可以应用任何建议的解决方案。我个人会尽可能寻求Christian C.Salvadó的第一个解决方案(当您不需要隐私时)。由于问题是关于最简单,最简洁的问题,所以这就是赢家。甚至:
var myInstance = {}; // Done!
(引用我的博客)...
var SingletonClass = new function() {
this.myFunction() {
// Do stuff
}
this.instance = 1;
}
没什么意义(我的博客示例也没有),因为它没有t不需要任何私有变量,因此与以下内容几乎相同:
var SingletonClass = {
myFunction: function () {
// Do stuff
},
instance: 1
}
评论
代码段2包含语法错误。您不能写this.f(){}
–xoxox
16年11月6日在21:19
#8 楼
我不赞成使用我的答案,请参阅其他答案。通常,单例模式不是很好的模块模式(请参见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();
};
};
评论
如果不需要模块,为什么还要加载该模块?而当您需要加载模块时,则加载模块,并对其进行初始化。
– Esailija
2013年11月17日19:27
#9 楼
简短答案:由于JavaScript具有非阻塞性,因此JavaScript中的单例确实很难使用。全局变量也将在整个应用程序中为您提供一个实例,而无需所有这些回调,并且模块模式将内部构件轻轻地隐藏在接口后面。请参阅克里斯蒂安·C·萨尔瓦多(Christian C.Salvadó)的回答。整个应用程序中只有一个实例:它们的初始化被延迟到第一次使用。当您处理初始化成本很高的对象时,这确实是一件大事。昂贵的方法通常意味着I / O,而在JavaScript中的I / O始终意味着回调。
不要相信像
instance = singleton.getInstance()
这样的界面,它们都会错过重点。如果他们不进行回调,要在实例准备就绪时运行,那么在初始化程序进行I / O时它们将无法工作。
是的,回调总是比立即返回对象实例的函数调用难看。再说一遍:执行I / O时,必须执行回调。如果您不想执行任何I / O,则实例化足以在程序启动时进行。
示例1,廉价的初始化方法:
var singleton = function(initializer) {
var state = 'initial';
var instance;
var queue = [];
var instanceReady = function(createdInstance) {
state = 'ready';
instance = createdInstance;
while (callback = queue.shift()) {
callback(instance);
}
};
return function(callback) {
if (state === 'initial') {
state = 'waiting';
queue.push(callback);
initializer(instanceReady);
} else if (state === 'waiting') {
queue.push(callback);
} else {
callback(instance);
}
};
};
示例2,使用I进行初始化/ O:
在此示例中,
setTimeout
伪造了一些昂贵的I / O操作。这说明了为什么JavaScript中的单例确实需要回调。var singletonInitializer = function(instanceReady) {
var preparedObject = {property: 'value'};
// Calling instanceReady notifies the singleton that the instance is ready to use
instanceReady(preparedObject);
}
var s = singleton(singletonInitializer);
// Get the instance and use it
s(function(instance) {
instance.doSomething();
});
评论
通过对其他单例答案的试探和磨难,我发现了与此类似的结果代码。
– mheyman
2014年8月22日在18:21
出于某种原因,这是唯一对我有意义的答案。其他答案都让我想起了愚蠢的表演集,其中三名男子试图通过递归彼此的肩膀爬上四个人高的墙。
–蒂姆·奥美(Tim Ogilvy)
2014年11月25日13:42
回调堆栈是我真正需要的东西!谢谢!!
–蒂姆·奥美(Tim Ogilvy)
2014年11月25日14:08
这种方法实际上不会给您一个单例,例如:singleton(singletonInitializer)!== singleton(singletonInitializer)它们是两个不同的实例。您返回的结果函数可用于将更多回调附加到该实例,但未严格指定只能创建此类型的一个实例。这就是单例的重点。
–欧文
2015年5月12日14:47
#10 楼
我从* JavaScript Patterns通过编码和设计模式构建更好的应用程序一书(由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
此方法通过了所有测试用例,而使用原型扩展时私有的静态实现将失败(可以固定,但不会很简单),并且由于实例暴露给公众的静态实现不建议public。
js完美演示。
#11 楼
Christian C.Salvadó和zzzzBov的答案都给出了很好的答案,但是只是基于我从单例模式很常见的PHP / Zend Framework转移到沉重的Node.js开发中来添加自己的解释。以下内容,评论-记录的代码基于以下要求:
只能实例化功能对象的一个实例
该实例不是公共可用的,并且只能通过公共方法进行访问
构造函数不是公开可用的,并且只有在没有可用实例的情况下才可以实例化
构造函数的声明必须允许修改其原型链。这将允许构造函数从其他原型继承,并为实例提供“公共”方法
我的代码与zzzzBov的答案非常相似,只不过我已向构造函数添加了原型链,并添加了更多注释这将帮助那些来自PHP或类似语言的人将传统的OOP转换为JavaScript的原型性质。
// Declare 'Singleton' as the returned value of a self-executing anonymous function
var Singleton = (function () {
"use strict";
// 'instance' and 'constructor' should not be available in a "public" scope
// here they are "private", thus available only within
// the scope of the self-executing anonymous function
var _instance=null;
var _constructor = function (name) {
this.name = name || 'default';
}
// Prototypes will be "public" methods available from the instance
_constructor.prototype.getName = function () {
return this.name;
}
// Using the module pattern, return a static object
// which essentially is a list of "public static" methods
return {
// Because getInstance is defined within the same scope
// it can access the "private" 'instance' and 'constructor' vars
getInstance:function (name) {
if (!_instance) {
console.log('creating'); // This should only happen once
_instance = new _constructor(name);
}
console.log('returning');
return _instance;
}
}
})(); // Self execute
// Ensure 'instance' and 'constructor' are unavailable
// outside the scope in which they were defined
// thus making them "private" and not "public"
console.log(typeof _instance); // undefined
console.log(typeof _constructor); // undefined
// Assign instance to two different variables
var a = Singleton.getInstance('first');
var b = Singleton.getInstance('second'); // passing a name here does nothing because the single instance was already instantiated
// Ensure 'a' and 'b' are truly equal
console.log(a === b); // true
console.log(a.getName()); // "first"
console.log(b.getName()); // Also returns "first" because it's the same instance as 'a'
请注意,从技术上讲,自执行匿名函数本身就是一个单例,正如Christian C提供的代码很好地展示了萨尔瓦多这里唯一要注意的是,当构造函数本身是匿名的时,不可能修改构造函数的原型链。
请记住,对于JavaScript,“ public”和“ private”的概念不适用于他们使用PHP或Java。但是我们通过利用JavaScript的功能范围可用性规则达到了相同的效果。
评论
可以从您的代码创建多个实例:var a = Singleton.getInstance('foo'); var b = new a.constructor('bar');
–zzzzBov
13年11月21日在14:42
@zzzzBov:在我的小提琴中尝试时遇到了错误:jsfiddle.net/rxMu8
–cincodenada
2014年5月23日18:47
#12 楼
我想我已经找到了使用JavaScript编程的最简洁方法,但是您需要一些想象力。我是从JavaScript:The Good Parts一书中的一种工作技巧中得到这个想法的。您可以创建一个像这样的类,而不是使用new关键字:
function Class()
{
var obj = {}; // Could also be used for inheritance if you don't start with an empty object.
var privateVar;
obj.publicVar;
obj.publicMethod = publicMethod;
function publicMethod(){}
function privateMethod(){}
return obj;
}
您可以实例化以上内容对象说:
var objInst = Class(); // !!! NO NEW KEYWORD
现在牢记这种工作方法,您可以创建一个单例:
ClassSingleton = function()
{
var instance = null;
function Class() // This is the class like the above one
{
var obj = {};
return obj;
}
function getInstance()
{
if( !instance )
instance = Class(); // Again no 'new' keyword;
return instance;
}
return { getInstance : getInstance };
}();
现在您可以通过调用
来获取实例
var obj = ClassSingleton.getInstance();
我认为这是最整洁的方法,因为甚至无法访问完整的“类”。
评论
但是使用这种技术,您可以拥有多个实例。那是不对的。
–nicolascolman
17年6月23日在16:18
我不这么认为,您甚至不通过getInstance就无法访问该类。你能详细说明吗?
–大卫
17年6月24日在17:11
大卫·梅斯(David Maes)抱歉,在第二个示例中,我没有注意到该验证。我道歉。
–nicolascolman
17年6月26日在10:07
#13 楼
您可以这样做:var singleton = new (function() {
var bar = 123
this.foo = function() {
// Whatever
}
})()
评论
这似乎是跳过getInstance方法并获得更简单解决方案的一种好方法。但是请记住,单例将在文件解析后立即执行,这意味着DOM侦听器必须包装在$(document).ready函数中。
– HoffZ
18年2月16日在14:21
#14 楼
最清楚的答案应该是Addy Osmani的《学习JavaScript设计模式》一书中的答案。 var mySingleton = (function () {
// Instance stores a reference to the singleton
var instance;
function init() {
// Singleton
// Private methods and variables
function privateMethod(){
console.log( "I am private" );
}
var privateVariable = "I'm also private";
var privateRandomNumber = Math.random();
return {
// Public methods and variables
publicMethod: function () {
console.log( "The public can see me!" );
},
publicProperty: "I am also public",
getRandomNumber: function() {
return privateRandomNumber;
}
};
};
return {
// Get the singleton instance if one exists
// or create one if it doesn't
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();
#15 楼
这应该起作用:function Klass() {
var instance = this;
Klass = function () { return instance; }
}
评论
测试=克拉斯; t1 = new Test(); t2 = new Test(); -没有机会重命名类或选择其他名称空间。
–zzzzBov
2012年12月3日在21:37
@zzzzBov我不太明白您要说的话。您是说不允许其他功能引用“ Singleton”功能吗?该解决方案有什么问题?
– Sudhansu Choudhary
8月6日19:15
@SudhansuChoudhary,坦率地说,八年前写这本书时,我无法准确说出自己的想法。如果我不得不猜测的话,这可能是因为该解决方案在全球名称空间中使用时的脆弱性,这在2012年是很普遍的。采用现代脚本实践,这种抱怨似乎不再相关,但是我要补充一点,这并不是2020年在JS中使用singleton的好主意(2012年也不是好主意)。
–zzzzBov
8月6日20:36
@zzzzBov我也不是一个Singleton粉丝,现在我知道当您发表评论时您来自何处,全局命名空间中解决方案的脆弱性应该引起人们的极大关注。感谢您的澄清。
– Sudhansu Choudhary
8月11日9:31
#16 楼
我相信这是最简单/最简洁,最直观的方式,尽管它需要ECMAScript 2016(ES7):export default class Singleton {
static instance;
constructor(){
if(instance){
return instance;
}
this.state = "duke";
this.instance = this;
}
}
源代码来自:adam-bien.com
评论
这是完全错误的,并且在调用新的Singleton()时会引发错误。
– UtkarshPramodGupta
1月20日13:02
#17 楼
我的两分钱:我有一个构造函数(CF),例如,var A = function(arg1){
this.arg1 = arg1
};
我只需要此CF创建的每个对象都相同。
var X = function(){
var instance = {};
return function(){ return instance; }
}();
Test
var x1 = new X();
var x2 = new X();
console.log(x1 === x2)
#18 楼
这是一个简单的示例,用于解释JavaScript中的单例模式。var Singleton = (function() {
var instance;
var init = function() {
return {
display:function() {
alert("This is a singleton pattern demo");
}
};
};
return {
getInstance:function(){
if(!instance){
alert("Singleton check");
instance = init();
}
return instance;
}
};
})();
// In this call first display alert("Singleton check")
// and then alert("This is a singleton pattern demo");
// It means one object is created
var inst = Singleton.getInstance();
inst.display();
// In this call only display alert("This is a singleton pattern demo")
// it means second time new object is not created,
// it uses the already created object
var inst1 = Singleton.getInstance();
inst1.display();
#19 楼
我发现以下是最简单的单例模式,因为使用new运算符使它可以立即在函数中使用,而无需返回对象文字: var singleton = new (function () {
var private = "A private value";
this.printSomething = function() {
console.log(private);
}
})();
singleton.printSomething();
#20 楼
对我来说,最简单/最简洁的方法也意味着简单地理解,并且不会像Java讨论版中所讨论的那样烦恼:在Java中实现单例模式的有效方法是什么?
从我的角度来看,最合适/最简单的答案是:
乔纳森(Jonathan)对在Java中实现单例模式的有效方法是什么的答案?
它只能部分翻译为JavaScript。 JavaScript的一些区别是:
构造函数不能是私有的
类不能具有声明的字段
但是鉴于最新的ECMA语法,它是可能与以下内容接近:
作为JavaScript类示例的单例模式
class Singleton {
constructor(field1,field2) {
this.field1=field1;
this.field2=field2;
Singleton.instance=this;
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance=new Singleton('DefaultField1','DefaultField2');
}
return Singleton.instance;
}
}
示例用法
console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);
示例结果
DefaultField1
DefaultField2
评论
我查看了广为接受的答案,但我认为这个答案没有得到足够的重视。 +1 btw
– Davood Falahati
10月17日23:33
我是来自Java的JavaScript的新手,必须问,这样做如何停止执行新的Singleton(),因此Singleton模式被破坏了
– Erik
10月26日8:01
@Erik-不是按照惯例,您调用getInstance
– Wolfgang Fahl
10月26日8:45
#21 楼
对我而言,最干净的方法是:const singleton = new class {
name = "foo"
constructor() {
console.log(`Singleton ${this.name} constructed`)
}
}
使用此语法,您可以确定自己的单身身份并将保持唯一。您还可以享受类语法的甜味,并按预期使用
this
。(请注意,类字段需要节点v12 +或现代浏览器。)
#22 楼
如果要使用类:class Singleton {
constructor(name, age) {
this.name = name;
this.age = age;
if(this.constructor.instance)
return this.constructor.instance;
this.constructor.instance = this;
}
}
let x = new Singleton('s', 1);
let y = new Singleton('k', 2);
上述输出将是:
console.log(x.name, x.age, y.name, y.age) // s 1 s 1
使用函数编写单例的另一种方法
function AnotherSingleton (name,age) {
this.name = name;
this.age = age;
if(this.constructor.instance)
return this.constructor.instance;
this.constructor.instance = this;
}
let a = new AnotherSingleton('s', 1);
let b = new AnotherSingleton('k', 2);
上面将是:
console.log(a.name, a.age, b.name, b.age) // s 1 s 1
#23 楼
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
#24 楼
我需要以下几个单例:惰性初始化
初始参数
所以这就是我想出的: br />
args
必须是Array才能起作用,因此,如果您有空变量,只需传入[]
我在函数中使用了window对象可以传入一个参数来创建我自己的作用域
名称,并且构造参数只是String才能使window []正常工作,但是需要进行一些简单的类型检查,window.name和window .construct也可以。
#25 楼
模块模式:“更具可读性”。您可以轻松查看哪些方法是公共方法,哪些是私有方法var module = (function(_name){
/* Local Methods & Values */
var _local = {
name : _name,
flags : {
init : false
}
}
function init(){
_local.flags.init = true;
}
function imaprivatemethod(){
alert("Hi, I'm a private method");
}
/* Public Methods & variables */
var $r = {}; // This object will hold all public methods.
$r.methdo1 = function(){
console.log("method1 calls it");
}
$r.method2 = function(){
imaprivatemethod(); // Calling private method
}
$r.init = function(){
inti(); // Making 'init' public in case you want to init manually and not automatically
}
init(); // Automatically calling the init method
return $r; // Returning all public methods
})("module");
现在您可以使用诸如
module.method2();之类的公共方法。 //->我通过公共方法alert(“嗨,我是私有方法”)调用私有方法
http://jsfiddle.net/ncubica/xMwS9/
#26 楼
另一种方法-确保该类不再是新的。这样,您可以使用
instanceof
op。另外,您可以使用原型链继承类。这是一门普通的课,但是你不能补习。如果要获取实例,请使用getInstance
:function CA()
{
if(CA.instance)
{
throw new Error('can not new this class');
}
else
{
CA.instance = this;
}
}
/**
* @protected
* @static
* @type {CA}
*/
CA.instance = null;
/* @static */
CA.getInstance = function()
{
return CA.instance;
}
CA.prototype =
/** @lends CA# */
{
func: function(){console.log('the func');}
}
// Initialise the instance
new CA();
// Test here
var c = CA.getInstance()
c.func();
console.assert(c instanceof CA)
// This will fail
var b = new CA();
如果不想公开
instance
成员,只需将其放入闭包中。#27 楼
function Unicode()
{
var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
// Loop through code points
while (i < max) {
// Convert decimal to hex value, find the character,
// and then pad zeroes to the code point
unicode[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
i = i + 1;
}
// Replace this function with the resulting lookup table
Unicode = unicode;
}
// Usage
Unicode();
// Lookup
Unicode["%"]; // Returns 0025
#28 楼
以下是我实现单例模式的摘录。这是我在面试过程中发生的,我觉得应该把它捕捉到某个地方。#29 楼
这也是一个单例:function Singleton() {
var i = 0;
var self = this;
this.doStuff = function () {
i = i + 1;
console.log('do stuff', i);
};
Singleton = function () { return self };
return this;
}
s = Singleton();
s.doStuff();
#30 楼
您可以像下面的示例中那样使用装饰器来完成TypeScript的操作:class YourClass {
@Singleton static singleton() {}
}
function Singleton(target, name, descriptor) {
var instance;
descriptor.value = () => {
if(!instance) instance = new target;
return instance;
};
}
然后您可以像这样使用单例:
var myInstance = YourClass.singleton();
在撰写本文时,装饰器尚不可用在JavaScript引擎中。您需要确保JavaScript运行时实际上启用了装饰器,或使用Babel和TypeScript之类的编译器。
还请注意,单例实例是“惰性”创建的,即仅在第一个实例中使用时才创建时间。
评论
TypeScript不是编译器。它是一种编程语言。您可以澄清(通过编辑答案)吗?
– Peter Mortensen
12月19日23:09
评论
拒绝接受的答案根本不是单例。这只是一个全局变量。这是大量信息,但实际上列出了不同JS设计模式之间的差异。它对我有很大帮助:addyosmani.com/resources/essentialjsdesignpatterns/book