用JavaScript实现单例模式的最简单/最干净的方法是什么?
当前回答
在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' }
其他回答
下面是我实现单例模式的演练片段。这是我在面试过程中想到的,我觉得我应该在某个地方捕捉到这一点。
/*************************************************
* SINGLETON PATTERN IMPLEMENTATION *
*************************************************/
// Since there aren't any classes in JavaScript, every object
// is technically a singleton if you don't inherit from it
// or copy from it.
var single = {};
// Singleton Implementations
//
// Declaring as a global object...you are being judged!
var Logger = function() {
// global_log is/will be defined in the GLOBAL scope here
if(typeof global_log === 'undefined'){
global_log = this;
}
return global_log;
};
// The below 'fix' solves the GLOABL variable problem, but
// the log_instance is publicly available and thus can be
// tampered with.
function Logger() {
if(typeof Logger.log_instance === 'undefined') {
Logger.log_instance = this;
}
return Logger.log_instance;
};
// The correct way to do it to give it a closure!
function logFactory() {
var log_instance; // Private instance
var _initLog = function() { // Private init method
log_instance = 'initialized';
console.log("logger initialized!")
}
return {
getLog : function(){ // The 'privileged' method
if(typeof log_instance === 'undefined') {
_initLog();
}
return log_instance;
}
};
}
/***** TEST CODE ************************************************
// Using the Logger singleton
var logger = logFactory(); // Did I just give LogFactory a closure?
// Create an instance of the logger
var a = logger.getLog();
// Do some work
// Get another instance of the logger
var b = logger.getLog();
// Check if the two logger instances are same
console.log(a === b); // true
*******************************************************************/
同样可以在我的主旨页面上找到。
另一种方法-只是确保类不能再新的。
这样,您就可以使用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
对我来说,最干净的方法是:
const singleton = new class {
name = "foo"
constructor() {
console.log(`Singleton ${this.name} constructed`)
}
}
使用这种语法,您可以确定您的单例是并且将保持惟一的。您还可以享受类语法的甜蜜,并按预期使用它。
(注意,类字段需要节点v12+或现代浏览器。)
我反对我的回答,看看我的另一个。
通常,模块模式(参见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();
};
};
然后我可以做以下事情:
window.iAmSingleton = singleton(function() {
/* This function should create and initialize singleton. */
alert("creating");
return {property1: 'value1', property2: 'value2'};
});
alert(window.iAmSingleton().property2); // "creating" will pop up; then "value2" will pop up
alert(window.iAmSingleton().property2); // "value2" will pop up but "creating" will not
window.iAmSingleton().property2 = 'new value';
alert(window.iAmSingleton().property2); // "new value" will pop up
推荐文章
- 给一个数字加上st, nd, rd和th(序数)后缀
- 函数可以作为参数传递吗?
- 如何以编程方式触发引导模式?
- setTimeout带引号和不带括号的区别
- 在JS的Chrome CPU配置文件中,'self'和'total'之间的差异
- 用javascript检查输入字符串中是否包含数字
- 如何使用JavaScript分割逗号分隔字符串?
- 在Javascript中~~(“双波浪号”)做什么?
- 谷歌chrome扩展::console.log()从后台页面?
- 未捕获的SyntaxError:
- [].slice的解释。调用javascript?
- jQuery日期/时间选择器
- 我如何预填充一个jQuery Datepicker文本框与今天的日期?
- 数组的indexOf函数和findIndex函数的区别
- jQuery添加必要的输入字段