轻松掌握:JavaScript单例模式

单例模式

定义:保证一个对象(类)仅有一个实例,并提供一个访问它的全局访问点;

实现原理:利用闭包来保持对一个局部变量的引用,这个变量保存着首次创建的唯一的实例;

主要用于:全局缓存、登录浮窗等只需要唯一一个实例的时候;

一. 为一个非单例模式对象(如: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设计模式与开发实践》

posted on 2016-08-24 23:41  SuriFuture  阅读(282)  评论(0编辑  收藏  举报

导航