javascript单例模式的理解

javascript单例模式的理解javascript

阅读目录html

理解单例模式java

单例模式的含义是: 保证一个类只有一个实例,并提供一个访问它的全局访问点。实现的方法是:使用一个变量来标志当前是否已经为某个类建立过对象,若是建立了,则在下一次获取该类的实例时,直接返回以前建立的对象,不然就建立一个对象。这就确保了一个类只有一个实例对象。缓存

好比以下代码是一个简单的单例模式代码实例:app

var Singleton = function(name){
    this.name = name;
    // 使用instance 该标志来判断是否建立了一个实例
    this.instance = null; 
};
Singleton.prototype.getName = function(){
    console.log(this.name);
};
Singleton.getInstance = function(name) {
    if(!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance;
}

如今咱们能够来使用下,初始化下,以下代码:dom

var a = Singleton.getInstance("aa");
var b = Singleton.getInstance("bbb");
console.log(a);
console.log(b);

打印以下:函数

继续以下测试:测试

console.log(a === b);  // true

a.getName();  // aa

b.getName();  // aa

a.test = "test";

console.log(b.test); // test

如上代码测试,能够看到,先是实例化一次,传aa给name参数,保存到a变量中,第二次再次调用getIstance方法,因为实例已经存在,因此使用以前第一次建立过的对象,所以 a ===b 为true,a.getName()和b.getName()值打印都为aa;this

咱们还能够像以下方式来编写代码:spa

var Singleton = function(name){
    this.name = name; 
};
Singleton.prototype.getName = function(){
    console.log(this.name);
};
Singleton.getInstance = (function(){
    var instance = null;
    return function(name){
        if(!instance) {
            instance = new Singleton(name);
        }
        return instance;
    }
})();

使用代理实现单例模式

好比我如今想在页面上建立一个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("aa");
var b = new ProxySingletonCreateDiv("bbb");
console.log(a === b); // true

如上代码:咱们把负责管理单例的逻辑移到了ProxySingletonCreateDiv 函数中,CreateDiv函数就是一个普通的函数,就是只是负责建立div的方法,那么具体的管理单例的逻辑交给ProxySingletonCreateDiv函数;

理解惰性单例

惰性单例的含义是:在须要的时候才建立对象实例,而前面咱们讲的是页面加载完的时候就建立实例;好比咱们在页面上一个弹出窗口的div,还有许多其余的显示元素,若是有些用户不点击那个弹窗的话,那么在页面初始化的时候多建立了一些dom节点,若是咱们使用惰性单例的话,咱们就能够在用户须要的时候才去建立dom节点;

咱们首先来看看在页面加载完成的时候去建立div弹窗。这个弹窗一开始是隐藏的,当用户点击某个按钮的时候,这个弹窗才显示;代码以下:

<button id="btn">请点击我</button>

var CreateDiv = (function(){
    var div = document.createElement('div');
    div.innerHTML = "我是弹窗测试";
    div.style.display = "none";
    document.body.appendChild(div);
    return div;
})();
document.getElementById("btn").onclick = function(){
    CreateDiv.style.display = "block";    
};
惰性代码以下所示:
var CreateDiv = function(){
    var div = document.createElement('div');
    div.innerHTML = "我是弹窗测试";
    div.style.display = "none";
    document.body.appendChild(div);
    return div;
};
document.getElementById("btn").onclick = function(){
    var createDiv = CreateDiv();
    createDiv.style.display = "block";    
};

如上代码,咱们点击按钮的时候,才去建立div元素,可是每次点击的时候,咱们都得建立元素,这样也不合理的。可是如上代码,咱们可使用一个变量来判断是否已经建立过div弹窗;以下所示:

var CreateDiv = (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("btn").onclick = function(){
    var createDiv = CreateDiv();
    createDiv.style.display = "block";    
};

编写通用的惰性单例

如上代码虽然完成了惰性单例,可是有些问题;

  1. 违反了单一职责原则;好比建立对象和管理单例的逻辑都放在CreateDiv对象内部;
  2. 没有把代码抽象出来,好比上面的是建立一个div元素,可是之后我想建立一个script元素或者一个iframe元素的话,那么咱们还须要复制上面的代码重写下;

好比若是我如今按照上面建立div的方法,如今咱们须要再建立一个iframe元素的话,代码须要改为以下:

var createIframe = (function(){
    var iframe;
    return function(){
        if(!iframe) {
            iframe = document.createElement('iframe');
            iframe.style.display = 'none';
            document.body.appendChild(iframe);
        }
        return iframe;
    }
})();

咱们如今确定在考虑如何把上面的代码公用出来,这样就能够实现抽象的代码,管理单例的逻辑代码其实能够抽象出来,这个逻辑是同样的,使用一个变量来标志是否建立过对象,若是是,在下次直接返回这个已经建立好的对象;

咱们能够把这些逻辑封装在getSingle函数内部,建立对象的方法fn被当成参数动态传入getSingle函数;以下代码:

var getSingle = function(fn){
    var result;
    return function(){
        return result || (fn.apply(this,arguments));
    };
};

下面咱们是使用getSingle建立一个div的方法以下:

var CreateDiv = function(){
    var div = document.createElement('div');
    div.innerHTML = "我是弹窗测试";
    div.style.display = "none";
    document.body.appendChild(div);
    return div;
};
// 建立单例
var createSingleDiv = getSingle(CreateDiv); 

document.getElementById("btn").onclick = function(){
    // 调用单例方法
    var createDiv = createSingleDiv();
    createDiv.style.display = "block";    
};

好比如今咱们须要建立一个iframe,那么代码以下:

var createSingleIframe = getSingle(function(){
    var iframe = document.createElement('iframe');
    document.body.appendChild(iframe);
    return iframe;
});
document.getElementById("btn").onclick = function(){
    // 调用单例方法
    var createSingleIframe = createSingleIframe();
    createSingleIframe.src = "http://cnblogs.com";    
};

单例模式使用场景

有一些对象咱们只须要一个的状况下,好比弹窗这样的,全局缓存,游览器window对象等。

单例模式只会建立一个实例,且仅有一个实例,好比咱们一刚开始讲到的,

var a = Singleton.getInstance("aa");

var b = Singleton.getInstance("bbb");

console.log(a === b);  // true

a.getName();  // aa

b.getName();  // aa

咱们明明第一次传的是aa,第二次传的参数是bbb,为何都调用getName()方法后都打印出aa呢,这就是单例模式只建立一个实例的地方;

相关文章
相关标签/搜索