想必大家都知道單例模式就是不管調用多少次new命令,始終只能創建一個實例對象。
寫個方法來看看javaScript的單例長什麼樣。
下面這個例子是負責在頁面中創建唯一的div節點。代碼如下
var CreateDiv = (function(){
var instance;
var CreateDiv = function(html){
if(instance){
return instance;
}
this.html = html;
this.init();
return instance = this;
}
CreateDiv.prototype.init=function(){
var div = document.createElement('div')
div.innerHtml = this.html;
document.body .appendChild(div)
}
return CreateDiv
})()
是不是跟你寫的不太一樣,是不是覺得這樣寫更好?
雖然這已經是優化過的js單例代碼,但是他依然有缺點:
爲了把instance封裝起來,我們使用了自執行的匿名函數和閉包,並且讓這個匿名函數返回真正的Singleton構造方法
這增加了一些程序的複雜度,閱讀起來比較費勁。
觀察這個Singleton構造函數
var CreateDiv = function(html){
if(instance){
return instance;
}
this.html = html;
this.init();
return instance = this;
}
它實際負責了兩件事情1:創建對象和執行初始化init方法。2:保證只有一個對象。這與‘單一指責原則’違背
用代理模式實現單一職責的單例
var CreateDiv = function(html){
this.html = html;
this.init();
}
CreateDiv.prototype.init=function(){
var div = document.createElement('div')
div.innerHtml= this.html;
document.body.appendChild(div);
}
接下來引入代理類proxySingletonCreateDiv
var ProxySingletonCreateDiv = (function(){
var instance;
return function(html){
if(!instance){
instance = new CreateDiv(html)
}
return instance
}
})()
通過引入代理類的方式實現了單一職責的單例模式。噢耶~~~
CreateDiv只負責創建對象和初始化。ProxySingletonCreateDiv負責保證只有一個對象。
// 創建一個dog單例 來鞏固一下
var Dog = function(name){
this.name = name;
this.init();
}
Dog.prototype.init=function(){
console.log('I am dog, my name is '+this.name)
}
var ProxySingletonCreateDog = (function(name){
var instance
return function (name){
if(!instance){
instance = new Dog(name)
}
return instance
}
})()
但是但是!上面的例子更多的接近傳統的面向對象的語言實現,而javascript是一門無類語言,生搬單例模式並無意義 嗚嗚嗚。
在javascript中創建單例模式非常的簡單,既然我們只需要一個唯一的對象,爲什麼要爲它創建一個類呢???這無異於穿衣服洗澡,傳統的單例模式實現在JavaScript中並不適用!!
單例模式的核心1 保證只有一個實例2提供全局訪問方法
全局變量不是單例模式,但是我們經常把全局變量當成單例來使用。
全局變量會造成命名空間污染,內存溢出等問題,所以儘量少使用全局變量。
我們可以使用閉包來實現單例
var User = (function(){
var _name = 'stupidcc';
var _age = 18;
return {
getName: function(){
return _name
},
getAge: function () {
return _age
},
setAge: function(age){
_age = age
}
}
})()
惰性單例
惰性是單例模式的重點,重點哦。
這種技術在開發過程中非常有用,有用程度可能超出了你的想象。
例如我們需要在頁面中創建一個iframe,使用單例
// 代理
var getSingleton = function(fn){
var result;
return function (fn) {
return result || (result = fn.apply(this,arguments))
}
}
var initIframe = function () {
var iframe = document.createElement('iframe')
document.body.appendChild(iframe)
return iframe
}
var CreateSingletonIframe = getSingleton(initIframe)
document.getElementById('button').onclick=function(){
var iframeObj = CreateSingletonIframe()
}