本文不单单是对于单例模式的总结,在最后还有对通用惰性单例的探讨和完善,不想看单例模式基础总结的能够直接跳转到「通用的单例中间类」来看我对于网络上流传的通用惰性单例模式的想法javascript
用一个变量来标记当前的类是否建立过对象,若是没建立过,返回建立以后的实例,若是以前已经建立过,则返回以前建立过的实例。java
// 构造函数
function Singleton(name) {
this.name = name
this.instance = null
}
// 构造函数方法
Singleton.prototype.getName = () => {
console.info(this.name)
}
// 单例控制
Singleton.getInstance = (name) => {
if(!this.instance) {
this.instance = new Singleton(name)
}
return this.instance
}
const a = Singleton.getInstance('a')
const b = Singleton.getInstance('b')
console.info(a, b) // true
复制代码
也可使用闭包segmentfault
// 构造函数
function Singleton(name) {
this.name = name
}
// 构造函数方法
Singleton.prototype.getName = function() {
console.info(this.name)
}
// 获取类的实例
Singleton.getInstance = (function() {
let instance = null
return function(name) {
if(!instance) {
instance = new Singleton(name)
}
return instance
}
})()
// 获取对象1
var a = Singleton.getInstance('a')
// 获取对象2
var b = Singleton.getInstance('b')
// 进行比较
console.info(a, b)
复制代码
固然也可使用 ES6 的 class
网络
class Singleton {
constructor(name) {
this.name = name
}
getName() {
console.info(this.name)
}
getInstance = (function(){
let instance = null
return function(name) {
if(!instance) {
instance = new Singleton(name)
}
return instance
}
})()
}
// 获取对象1
var a = Singleton.getInstance('a')
// 获取对象2
var b = Singleton.getInstance('b')
// 进行比较
console.info(a, b)
复制代码
可是此方法必需要使用 Singleton.getInstance()
才能获取到想要的实例,这与咱们习觉得常的 new
关键字获取实例对象有很大区别。其实这种方法的实现思路就是用构造函数中的一个方法去控制此构造函数生成的实例为单例,既然咱们想要用 new
关键字来生成单例,那咱们为什么不用另外一个构造函数来控制此构造函数的建立呢闭包
class Person {
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
const Singleton = (function() {
let instance
return function(name) {
if(!instance) {
instance = new Person(name)
}
return instance
}
})()
// 获取对象1
let a = new Singleton('a')
let b = new Singleton('b')
console.info(a === b) // true
复制代码
以上中间控制方法或类中的构造函数都是固定的,也就是说咱们须要为不一样的构造函数编写不一样的中间方法或类,这样显然是不合理的。app
我发现如今流传在网上的基本上是以下这种函数
// 获取单独的实例
var singleton = function(fn) {
var instance;
return function() {
return instance || (instance = fn.apply(this, arguments));
}
}
// 建立遮罩层
var createMask = function(){
// 建立div元素
var mask = document.createElement('div');
// 设置样式
mask.style.position = 'fixed';
mask.style.top = '0';
mask.style.right = '0';
mask.style.bottom = '0';
mask.style.left = '0';
mask.style.opacity = 'o.75';
mask.style.backgroundColor = '#000';
mask.style.display = 'none';
mask.style.zIndex = '98';
document.body.appendChild(mask);
// 单击隐藏遮罩层
mask.onclick = function(){
this.style.display = 'none';
}
return mask;
};
// 调用
var oMask = singleton(createMask)()
var eMask = singleton(createMask)()
// 可是 oMask 与 eMask 不相等,获取 eMask 时其实也建立了新的 div
复制代码
这种调用方法其实仅仅是获取到了 createMask
中的返回值,每次 singleton()
其实都会执行 var instance
,因此对 instance
的判断实际上是没用的。正确调用我以为应该以下ui
const maskSingleton = singleton(createMask) // 先用一个变量接一下
const oMask = maskSingleton()
const eMask = maskSingleton() // 此时返回的仍是以前已经建立的 mask
复制代码
但其实上面的例子并未很好的体现出通用惰性单例模式的做用,并且oMask
实际上是获取不到 createMask
原型链上的方法的「也可能本来做者就不想获取 = =」,但咱们以前的举例都是使用构造函数的举例,因此接下来我也会用构造函数的例子来展示。this
const singleton = function(Fn) {
var instance
return function() {
return instance || (instance = new Fn(...arguments))
}
}
const Person = function(name){
this.name = name
}
Person.prototype.getName = function() {
return this.name
}
const Animal = function(name) {
this.name = name
}
Animal.prototype.getName = function() {
return this.name
}
const PersonSingleton = singleton(Person)
const liSi = PersonSingleton('liSi')
const zhangSan = PersonSingleton('zhangSan')
const AnimalSingleton = singleton(Animal)
const cat = AnimalSingleton('cat')
const dog = AnimalSingleton('dog')
console.info(zhangSan.getName()) // 'liSi'
console.info(dog.getName()) // 'cat'
复制代码
参考连接: segmentfault.com/a/119000001…spa