部分摘自《JavaScript设计模式与开发实践》
单例模式
单例保证一个类只有一个实例,实现方法是一般先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保一个类只有一个实例对象。在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象。(保证一个类仅有一个实例,并提供一个访问他的全局访问点)
单例的作用和注意事项
模式作用:
- 模块间通信;
- 系统中某个类的对象只能存在一个;
- 保护自己的属性和方法;
注意事项:
- 注意this的使用;
- 闭包容易造成内存泄漏,不需要的要赶快干掉;
- 注意new的成本;
实现
// 不透明的单例
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('zee1');
var b = Singleton.getInstance('zee2');
alert(a === b); // true;
// 透明的单例
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;
})();
以上的实现过程参考于传统面向对象语言。
JavaScript中的单例模式
// 1、使用命名空间
var namespace1 = {
a: function(){
alert(1);
},
b: function(){
alert(2);
}
}
// 动态创建命名空间
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 = 'zee';
_age = 29;
return {
getUserInfo: function(){
return _name + '-' + _age;
}
}
})();
惰性单例
惰性单例指的是在需要的时候才创建对象实例。(是单例模式的重点)
Singleton.getInstance = (function(){
var instance = null;
return function(name){
if(!instance) {
instance = new Singleton(name);
}
return instance;
}
})();
webQQ登录案例
<html>
<body>
<button id="loginBtn">登录</button>
</body>
<script>
var createLoginLayer = (function() {
var div;
return function(){
if(!div){
div = document.createElement('div');
div.innerHTML = '我是登录浮窗';
div.style.display = 'none';
document.body.appendChild(div);
}
return div;
}
})();
document.getElementById('loginBtn').onclick = function(){
var loginLayer = createLoginLayer();
loginLayer.style.display = 'block';
}
</script>
</html>
封装单例逻辑
var obj;
if(!obj){
obj = xxx;
}
var getSingle = function(fn){
var result;
return function(){
return result || (result = fn.apply(this, arguments));
}
};
------------------------------------------------------------------------------------------------
var createLoginLayer = function(){
var div = document.createElement('div');
div.innerHTML = '我是登录浮窗';
div.style.display = 'none';
document.body.appendChild('div');
return div;
};
var createSingleLoginLayer = getSingle(createLoginLayer);
document.getElementById('loginBtn').onclick = function(){
var loginLayer = createSingleLayer();
loginLayer.style.display = 'block';
}