用JavaScript实现单例模式的最简单/最干净的方法是什么?
当前回答
你可以用下面这个例子中的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这样的编译器。
还要注意的是,单例实例是“惰性”创建的,也就是说,只有当你第一次使用它时才会创建它。
其他回答
模块模式:“更具可读性的风格”。您可以很容易地看到哪些方法是公共的,哪些是私有的
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 ();// ->我正在调用一个私有方法超过一个公共方法警报(“嗨,我是一个私有方法”)
http://jsfiddle.net/ncubica/xMwS9/
如果你想使用类:
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
另一种方法-只是确保类不能再新的。
这样,您就可以使用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();
如果不想公开实例成员,只需将其放入闭包中。
所以公平地说,最简单的答案通常是最好的。一个对象字面值总是一个实例。没有什么理由去做更复杂的事情,除了按需分配内存。
话虽如此,这里是一个使用ES6的经典单例实现。
实例“field”是“private”。这实际上意味着我们将实例隐藏为构造函数的属性。某个不是构造函数的地方。原型,它将通过原型继承对实例可用。 构造函数是“private”。当调用者不是静态getInstance方法时,我们实际上只是抛出一个错误。
同样值得注意。理解这个关键词在不同语境下的含义是很重要的。
在构造函数中,this指向创建的实例。
在静态getInstance方法中,this指向dot的左边,宇宙构造函数,它是一个对象,像JS中的大多数东西一样,可以保存属性。
class Universe { constructor() { if (!((new Error).stack.indexOf("getInstance") > -1)) { throw new Error("Constructor is private. Use static method getInstance."); } this.constructor.instance = this; this.size = 1; } static getInstance() { if (this.instance) { return this.instance; } return new this; } expand() { this.size *= 2; return this.size; } } console.log(Universe.getInstance()) console.log(Universe.getInstance().expand()) console.log(Universe.getInstance()) console.log(new Universe())
如果你正在使用node.JS,那么你可以利用node.JS的缓存机制,你的单例将像这样简单:
class Singleton {
constructor() {
this.message = 'I am an instance';
}
}
module.exports = new Singleton();
请注意,我们导出的不是类Singleton,而是实例Singleton()。
Node.JS将在每次需要时缓存和重用相同的对象。
更多细节请查看:Node.JS和单例模式
推荐文章
- Babel 6改变了它导出默认值的方式
- 如何配置历史记录?
- ES6模板文字可以在运行时被替换(或重用)吗?
- [Vue警告]:找不到元素
- 可以在setInterval()内部调用clearInterval()吗?
- AngularJS控制器的生命周期是什么?
- 无法读取未定义的属性“msie”- jQuery工具
- 我的蛋蛋怎么不见了?
- JavaScript中的排列?
- JavaScript中有睡眠/暂停/等待功能吗?
- 如何禁用文本选择使用jQuery?
- 如何停止事件冒泡复选框点击
- 如何在PHP中截断字符串最接近于一定数量的字符?
- 向对象数组添加属性
- 如何在Redux应用程序中动态加载代码分割的减速器?