單例模式
簡單的單例模式
通過一個getInstance方法獲取對象,首先判斷一個對象是否存在,如果存在則就將改對象返回,如果不存在就先實例化對象(創(chuàng)建對象),然后再返回
將實例存儲在對象中
let Singleton = function(name){
this.name = name;
}
// 將實例存儲在對象中
Singleton.getInstance = function() {
// 如果本身到
if(this.instance === null){
this.instance = new Singleton();
}
return this.instance;
}
let aIns = Singleton.getInstance("test");
let bIns = Singleton.getInstance("test");
console.log(aIns === bIns);
使用閉包存儲實例對象
// 將實例使用閉包的形式存儲起來
Singleton.getInstanceNew = (function() {
let instance = null;
return function(){
if(instance === null){
instance = new Singleton();
}
return instance;
}
}())
let cIns = Singleton.getInstanceNew("test");
let dIns = Singleton.getInstanceNew("test");
console.log(cIns === dIns, aIns === dIns);
我們看到以上兩個方法,都是創(chuàng)建單例的簡單方法,雖然實現了,但是如果別人不知道這個對象時單例的,還是可以使用new關鍵字創(chuàng)建。并且不再是單例了,所以很容易違背了我們單例的初心
透明的單例模式
我們依然通過new創(chuàng)建實例,但是創(chuàng)建的還是單例的,這樣即使不需要我們特意去囑咐這個對象是單例
var TransparentSingleton = (function() {
var instance = null;
var TransparentSingleton = function(){
if(instance){
return instance;
}
this.init();
return instance = this;
}
TransparentSingleton.prototype.init = function(){
console.log("Dom操作")
}
return TransparentSingleton;
}())
let eIns = new TransparentSingleton();
let fIns = new TransparentSingleton();
console.log(eIns === fIns);
這種方法雖然滿足了我們的要求,但是這里存在一個問題,就是內部的TransparentSingleton的這對象,成為了一個私有對象,我們在外面無法訪問到
代理版單例模式
var CreateDom = function(html){
this.html = html;
this.init();
}
CreateDom.prototype.init = function(){
console.log(this.html);
}
var ProxyCreateDom = (function(){
let instance = null;
return function(html){
if(instance === null){
instance = new CreateDom(html);
}
return instance;
}
}())
let hIns = new ProxyCreateDom("測試");
let gIns = new ProxyCreateDom("前端");
console.log(hIns === gIns, hIns.html, gIns.html)
這里我們將對象提了出來了,通過ProxyCreateDom去創(chuàng)建一個關于CreateDom的單例,但是這個版本是比較有限的,我們可以看到這個代理單例并不是一個可復用的,代碼很可能會翻倍。并且不管我們需不要單例,其實ProxyCreateDom里的instance就創(chuàng)建了。并且這個是屬于傳統面向對象語言的,在JavaScript這個沒有類的語言中,這樣創(chuàng)建意義并不大
惰性單例模式通用版本
let getSingleton = function(func) {
let result = null;
return function(){
return result || (result = func.apply(this, arguments));
}
}
function createLoginLayer(){
var div = document.createElement("div");
div.innerHTML = "我是登錄浮窗";
div.style.display = "none";
document.body.appendChild(div);
return div;
}
/**
* 測試代碼
*/
let createSingleLoginLayer = getSingleton(createLoginLayer);
// 添加一個登陸浮窗
document.getElementById("loginTest").onclick = function(){
var loginLayer = createSingleLoginLayer();
loginLayer.style.display = "block"
}
// 創(chuàng)建一個iframe的單例
var createSingleIfame = getSingleton(function () {
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
return iframe;
})
// 創(chuàng)建一個iframe,并將src屬性設置為百度
document.getElementById("loginBtn").onclick = function(){
var loginLayer = createSingleIfame();
loginLayer.src = "http://baidu,com";
}
// 將浮窗單例隱藏
document.getElementById("closeLoginBtn").onclick = function(){
var loginLayer = createSingleLoginLayer();
loginLayer.style.display = "none"
}
// 改變iframe的src屬性
document.getElementById("changeUrlBtn").onclick = function(){
var loginLayer = createSingleIfame();
loginLayer.src = "http://127.0.0.1:5500/index.html";
}
|