用JavaScript实现单例模式的最简单/最干净的方法是什么?
当前回答
另一种方法-只是确保类不能再新的。
这样,您就可以使用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();
如果不想公开实例成员,只需将其放入闭包中。
其他回答
如果你想使用类:
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
另一种使用函数编写Singleton的方法
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
这个知识是基于我正在学习Java,虽然Java和Javascript是不同的,但单例的概念和Java如何做到这一点是一样的。在我看来,JS的类样式本身是干净的,而不是var初始化。
class Singleton {
// use hashtag which entails that the variable can only be accessed from self scope
static #instance = null;
static getInstance() {
if (this.#instance === null) this.#instance = new Singleton();
return this.#instance;
}
// some class property
hello = 'world';
// or initialize the variable in the constructor, depend on your preference
constructor() {
// this.hello = 'world';
}
/* you can also add parameters on the constructor & getInstance
* e.g.
* static getInstance(param1, param2) {...new Singleton(param1, param2)}
* constructor(param1, param2) {...}
*/
}
// this is the same code for java and normal way for singleton for class
// just use static so you can get instance
// testing the singleton
var s1,s2;
s1 = Singleton.getInstance();
s2 = Singleton.getInstance();
// you cannot access the property, immediately
if (Singleton.hello === undefined) console.log('getInstance so you can access this');
console.log(s1.hello);
// result: "world"
console.log(s2.hello);
// result: "world"
// set the value of Singleton object
s2.hello = "hi";
console.log(s1.hello);
// result: "hi"
console.log(s2.hello);
// result: "hi"
// this is just an evidence which means that they are the same even in property level
if (s1 === s2) console.log("S1 & S2 is the same object");
// result: "S1 & S2 is the same object"
// don't use something like `var s1 = new Singleton();`
// this will defeat your purpose of just (1 object), one instance of class
这也是一个单例:
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();
使用ES6类和私有静态字段。调用Singleton类的新实例将返回相同的实例。实例变量也是私有的,不能在类外部访问。
class Singleton {
// # is a new Javascript feature that denotes private
static #instance;
constructor() {
if (!Singleton.#instance) {
Singleton.#instance = this
}
return Singleton.#instance
}
get() {
return Singleton.#instance;
}
}
const a = new Singleton();
const b = new Singleton();
console.log(a.get() === b.get()) // true
console.log(Singleton.instance === undefined) // 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 ) );
推荐文章
- Babel 6改变了它导出默认值的方式
- 如何配置历史记录?
- ES6模板文字可以在运行时被替换(或重用)吗?
- [Vue警告]:找不到元素
- 可以在setInterval()内部调用clearInterval()吗?
- AngularJS控制器的生命周期是什么?
- 无法读取未定义的属性“msie”- jQuery工具
- 我的蛋蛋怎么不见了?
- JavaScript中的排列?
- JavaScript中有睡眠/暂停/等待功能吗?
- 如何禁用文本选择使用jQuery?
- 如何停止事件冒泡复选框点击
- 如何在PHP中截断字符串最接近于一定数量的字符?
- 向对象数组添加属性
- 如何在Redux应用程序中动态加载代码分割的减速器?