单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”
这一模式的目的是使得类的一个对象成为系统中的唯一实例,并提供全局访问。
全局变量不是单例模式,但是在javascript开发中,我们经常会把全局变量当成单例来使用。但是全局变量会引起很多问题,很容易造成命名空间污染。
可以用以下方式可以相对降低全局变量带来的命名污染:
1.使用命名空间,减少全局变量的数量
最简单的方法是使用对象字面量的方式。
2.使用闭包封装私有变量
透明的单例模式
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( 'lily3' );
var b = new CreateDiv( 'lily2' );
alert( a=== b);
这段代码中CreateDiv的构造函数创建对象和初始化init方法。而且保证了只有一个单例。但是这个构造函数只能创建一个实例。如果想要创建多个实例,就不得不修改构造函数。
这里引入代理类的方式,使CreateDiv函数变成普通的创建div的类。使用代理类来实现管理单例的代码,两个类结合在一起就组成单例模式。
var CreateDiv =(function(){
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( 'lily1');
var b = new ProxySingletonCreateDiv( 'lily2' );
alert( a=== b );
上述的单例模式的实现是基于面向对象语言实现的。但是对于javascript这种无类的语言来说,传统的单例模式并不适用。
惰性单例
惰性单例是指在需要的时候才创建实例对象。
Singleton.getInstance = (function(){
var instance = null;
return function( name ){
if( !instance ){
instance = new Singleton( name );
}
return instance;
}
})();
</span>
以上代码还是基于类的单例模式。
下面我们将创建实例和管理单例功能分隔开。
将创建悬浮窗的方法作为参数传入getSingle,
<button id ="login">登录</button>
//将函数传入,并返回一个新的函数,并用变量result保存fn的计算结果,result在闭包中存在,所以不会被销毁,如果result已经存在,则直接返回这个值。
var getSingle = function( fn ){
var result;
return function(){
return result || (result = fn.apply( this, arguments));
};
};
//创建悬浮窗
var createLogin = function(){
var div = document.createElement( 'div' );
div.innerHTML = '登录悬浮窗';
div.style.display = 'none';
document.body.appendChild( div );
return div;
};
//<span style="font-family:KaiTi_GB2312;">将创建悬浮窗的方法作为参数传入getSingle</span>
var createSingleLogin = getSingle( createLogin );
//点击事件
document.getElementById( 'login' ).onclick = function(){
var login = createSingleLogin();
login.style.display = 'block';
};
文章总结自《javascript设计模式与开发实践》,以后会继续跟进自己的实践总结。