首先我们需要明白什么是单例模式:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏
览器中的 window 对象等。在 JavaScript开发中,单例模式的用途同样非常广泛。比如我们的弹窗需要一个遮罩背景,那么这个遮罩背景就适合用单例模式来创建了。
实现单例模式
比如我们实现一个单例创建背景div
var createDiv = (function() {
var div;
return function() {
if (!div) {
div = document.createElement('div')
}
return div;
}
})()
createDiv() === createDiv() //true
无论我们调用多少次createDiv都是同一个div,这就达到了单例的目的。
上述简答例子虽然创建了单例,但是是违反设计模式的单一职责原则的。这个方法既要管理单例,又要负责创建,不利于维护与修改。我们可以稍作改变便可改良:
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);
}
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变成一个普通的创建div的类。这样组合使用我们也实现了单例模式,这样做的好处是拆分了职责,以便我们在将来好维护与修改。比如我们需要在初始化的时候加一些样式啥的,那我们只要修改init函数即可。
javascript中的单例模式
上述单例模式我们是基于类的理念去设计的,但是在javascript中并没有类的概念,基于类的单例模式在javascript中并不适合,我们可以根据javascript的特点来设计适合JS的单例模式。
var getSingle = function( fn ){
var result;
return function(){
return result || ( result = fn .apply(this, arguments ) );
}
};
本段代码将单例管理方法抽象,使之不再创建具体的单例,而是由各自的实现方法去创建,这样我们传入不同的fn便可以创建不同的单例了。
比如:
var createIframe= (function(){
var iframe;
return function(){
if ( !iframe){
iframe= document.createElement( 'iframe' );
iframe.style.display = 'none';
document.body.appendChild( iframe);
}
return iframe;
}
})();
这样我们就创建了一个iframe,我们还可以用同样的方法创建各种标签。单例模式用途广泛,且简单实用是我们必须要掌握的设计模式之一。