本文不單單是對於單例模式的總結,在最後還有對通用惰性單例的探討和完善,不想看單例模式基礎總結的能夠直接跳轉到「通用的單例中間類」來看我對於網絡上流傳的通用惰性單例模式的想法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