单例模式
定义:保证一个对象(类)仅有一个实例,并提供一个访问它的全局访问点;
实现原理:利用闭包来保持对一个局部变量的引用,这个变量保存着首次创建的唯一的实例;
主要用于:全局缓存、登录浮窗等只需要唯一一个实例的时候;
一. 为一个非单例模式对象(如:Demo)实现单例模式的方法:
给Demo添加一个静态方法来实现单例:
Demo.getSingle = (function(){
var demo = null;
return function(name){
if(!demo){
demo = new Demo(name);
}
return demo;
}
})();
用法:
非单例模式:
var a = new Demo('Peter');
单例模式:
var b1 = Demo.getSingle('Peter');
var b2 = Demo.getSingle('Sufei');
b1 === b2;//true,都引用的是new Demo('Peter')
通过代理类来实现单例:
var ProxyDemo = (function(){
var demo = null;
return function(name){
if(!demo){
demo = new Demo(name);
}
return demo;
}
})();
用法:
非单例模式:
var a = new Demo('Peter');
单例模式:
var b = new ProxyDemo('Peter');
二. 惰性单例模式:只在需要的时候才创建该单例;
以下是通用惰性单例的创建方法:
var getSingle = function(foo){
var single = null;
return function(){
return single || (single = foo.apply(this,arguments));
}
};
用法:
var createLoginLayer = function(){
var frag = document.createDocumentFragment();
var div = document.createElement('div');
div.style.display = 'none';
//以下给div添加其它登录元素
...
document.body.appendChild(frag.appendChild(div));
return div;
}
var createSingleLoginLayer = getSingle(createLoginLayer);
//当用户第一次点击按钮(id = 'lgBtn')时,来创建并显示登录窗口,之后重复点击按钮不会重复创建;
document.getElementById('lgBtn').onclick = function(){
var lg = createSingleLoginLayer();
lg.style.display = 'block';
}
创建单例的其它方法:
方法1:
function Universe() {
// 判断是否存在实例
if (typeof Universe.instance === 'object') {
return Universe.instance;
}
// 其它内容
this.start_time = 0;
this.bang = "Big";
// 缓存
Universe.instance = this;
// 隐式返回this
}
// 测试
var uni = new Universe();
var uni2 = new Universe();
console.log(uni === uni2); // true
方法2:
function Universe() {
// 缓存的实例
var instance = this;
// 其它内容
this.start_time = 0;
this.bang = "Big";
// 重写构造函数
Universe = function () {
return instance;
};
}
附:缓存函数的计算结果,如计算一个数的数列
以下是不缓存的写法,非常慢!
function foo(n){
results = n < 2 ? n : foo(n - 1) + foo(n - 2);
return results;
}
console.log(foo(40));//得计算好几秒
以下是缓存写法,基本瞬间出结果!
var cache = {};
function foo(n){
if(!cache[n]){
cache[n] = n < 2 ? n : foo(n - 1) + foo(n - 2);
}
return cache[n];
}
console.log(foo(100));
更好的写法:
var foo = (function(){
var cache = {};
return function(n){
if(!cache[n]){
cache[n] = n < 2 ? n : foo(n - 1) + foo(n - 2);
}
return cache[n];
};
})();
console.log(foo(100));
参考文献:
《JavaScript模式》
《JavaScript设计模式与开发实践》