單例模式 保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。 單例模式是一種常用的模式,有一些對象我們往往只需要一個,比如線程池、全局緩存、瀏覽器中的 window 對象等。 JavaScript 中的單例模式 1. 使用命名空間 在JavaScript里,實現單例的方式有很多種,其中最簡單的一 ...
單例模式
保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
單例模式是一種常用的模式,有一些對象我們往往只需要一個,比如線程池、全局緩存、瀏覽器中的 window 對象等。
JavaScript 中的單例模式
1. 使用命名空間
在JavaScript里,實現單例的方式有很多種,其中最簡單的一個方式是使用對象字面量的方法,其字面量里可以包含大量的屬性和方法:
let people = {
name: "Jack",
age: 18,
play() {
console.log('i like game');
}
}
還可以動態地創建命名空間
// 定義對象
var MyApp = {};
// 對象的方法
MyApp.namespace = function( name ){
// 將參數分割成數組
var parts = name.split( '.' );
// 定義變數
var current = MyApp;
// 創建對象裡面的屬性
for ( var i in parts ){
if ( !current[ parts[ i ] ] ){
current[ parts[ i ] ] = {};
}
current = current[ parts[ i ] ];
}
};
MyApp.namespace( 'event' );
MyApp.namespace( 'dom.style' );
/******************* 上面沒看懂沒關係 ***********************/
// 上述代碼等價於
var MyApp = {
event: {},
dom: {
style: {}
}
};
2. 使用閉包封裝私有變數
var user = (function(){
var __name = 'sven',
__age = 29;
return {
getUserInfo: function(){
return __name + '-' + __age;
}
}
})();
我們用下劃線來約定私有變數 __name
和 __age
,它們被封裝在閉包產生的作用域中,外部是訪問不到這兩個變數的,這就避免了對全局的命令污染。
實現一個標準的單例模式
var Singleton = function( name ){
this.name = name;
this.instance = null;
};
Singleton.prototype.getName = function(){
alert ( this.name );
};
Singleton.getInstance = function( name ){
if ( !this.instance ){
this.instance = new Singleton( name );
}
return this.instance;
};
var a = Singleton.getInstance( 'sven1' );
var b = Singleton.getInstance( 'sven2' );
alert ( a === b ); // true
我們通過 Singleton.getInstance
來獲取 Singleton
類的唯一對象,這種方式相對簡單,但有一個問題,就是增加了這個類的“不透明性”, Singleton
類的使用者必須知道這是一個單例類,跟以往通過 new XXX
的方式來獲取對象不同,這裡偏要使用 Singleton.getInstance
來獲取對象。
透明的單例模式
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;
})();
var a = new CreateDiv( 'sven1' );
var b = new CreateDiv( 'sven2' );
alert ( a === b ); // true
為了把 instance
封裝起來,我們使用了自執行的匿名函數和閉包,並且讓這個匿名函數返回
真正的 Singleton
構造方法,這增加了一些程式的複雜度
3. 用代理實現單例模式
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;
}
})();
var a = new ProxySingletonCreateDiv( 'sven1' );
var b = new ProxySingletonCreateDiv( 'sven2' );
alert ( a === b );
通過引入代理類的方式,我們同樣完成了一個單例模式的編寫,跟之前不同的是,現在我們
把負責管理單例的邏輯移到了代理類 proxySingletonCreateDiv
中。這樣一來,CreateDiv
就變成了一個普通的類,它跟 proxySingletonCreateDiv
組合起來可以達到單例模式的效果。
惰性單例
惰性單例指的是在需要的時候才創建對象實例。
var Singleton = (function () {
var instantiated;
function init() {
/*這裡定義單例代碼*/
return {
publicMethod: function () {
console.log('hello world');
},
publicProperty: 'test'
};
}
return {
getInstance: function () {
if (!instantiated) {
instantiated = init();
}
return instantiated;
}
};
})();
/*調用公有的方法來獲取實例:*/
Singleton.getInstance().publicMethod();
通過以上方法我們就可以做到只有在使用的時候才初始化,從而達到節約資源的目的
目前對於單例模式的理解就這麼多,以後有了新的理解會繼續更新的,溜了溜了(~ ̄▽ ̄)~