用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 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'
// ...
剥猫皮的方法不止一种:)根据你的口味或特定需求,你可以应用任何一种建议的解决方案。我个人倾向于Christian C. Salvadó的第一个解决方案(当你不需要隐私的时候)。
因为这个问题是关于最简单和最干净的,所以这个问题是赢家。甚至:
var myInstance = {}; // Done!
这(引用自我的博客)……
var SingletonClass = new function() {
this.myFunction() {
// Do stuff
}
this.instance = 1;
}
没有太大的意义(我的博客例子也没有),因为它不需要任何私有变量,所以它几乎与:
var SingletonClass = {
myFunction: function () {
// Do stuff
},
instance: 1
}
我需要几个单人间:
延迟初始化 初始参数
这就是我想到的:
createSingleton ('a', 'add', [1, 2]);
console.log(a);
function createSingleton (name, construct, args) {
window[name] = {};
window[construct].apply(window[name], args);
window[construct] = null;
}
function add (a, b) {
this.a = a;
this.b = b;
this.sum = a + b;
}
args必须是Array,所以如果你有空变量,只需要传入[] 我在函数中使用了window对象,但我本可以传入一个参数来创建自己的作用域 name和构造参数只是字符串,以便window[]工作,但有一些简单的类型检查,window.name和window.name。构造也是可能的。
下面是我实现单例模式的演练片段。这是我在面试过程中想到的,我觉得我应该在某个地方捕捉到这一点。
/*************************************************
* 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
*******************************************************************/
同样可以在我的主旨页面上找到。
如果你想使用类:
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
推荐文章
- Babel 6改变了它导出默认值的方式
- 如何配置历史记录?
- ES6模板文字可以在运行时被替换(或重用)吗?
- [Vue警告]:找不到元素
- 可以在setInterval()内部调用clearInterval()吗?
- AngularJS控制器的生命周期是什么?
- 无法读取未定义的属性“msie”- jQuery工具
- 我的蛋蛋怎么不见了?
- JavaScript中的排列?
- JavaScript中有睡眠/暂停/等待功能吗?
- 如何禁用文本选择使用jQuery?
- 如何停止事件冒泡复选框点击
- 如何在PHP中截断字符串最接近于一定数量的字符?
- 向对象数组添加属性
- 如何在Redux应用程序中动态加载代码分割的减速器?