单例模式

  • A+
所属分类:Web前端
摘要

通过一个getInstance方法获取对象,首先判断一个对象是否存在,如果存在则就将改对象返回,如果不存在就先实例化对象(创建对象),然后再返回


单例模式

简单的单例模式

通过一个getInstance方法获取对象,首先判断一个对象是否存在,如果存在则就将改对象返回,如果不存在就先实例化对象(创建对象),然后再返回

将实例存储在对象中

let Singleton = function(name){   this.name = name; }  // 将实例存储在对象中 Singleton.getInstance = function() {    // 如果本身到   if(this.instance === null){     this.instance = new Singleton();   }   return this.instance; }  let aIns = Singleton.getInstance("test"); let bIns = Singleton.getInstance("test");  console.log(aIns === bIns); 

使用闭包存储实例对象

// 将实例使用闭包的形式存储起来 Singleton.getInstanceNew = (function() {    let instance = null;   return function(){     if(instance === null){       instance = new Singleton();     }     return instance;   }  }())    let cIns = Singleton.getInstanceNew("test"); let dIns = Singleton.getInstanceNew("test");  console.log(cIns === dIns, aIns === dIns); 

我们看到以上两个方法,都是创建单例的简单方法,虽然实现了,但是如果别人不知道这个对象时单例的,还是可以使用new关键字创建。并且不再是单例了,所以很容易违背了我们单例的初心

透明的单例模式

我们依然通过new创建实例,但是创建的还是单例的,这样即使不需要我们特意去嘱咐这个对象是单例

var TransparentSingleton = (function() {    var instance = null;    var TransparentSingleton = function(){       if(instance){         return instance;       }       this.init();       return instance = this;    }      TransparentSingleton.prototype.init = function(){     console.log("Dom操作")   }    return TransparentSingleton; }())   let eIns = new TransparentSingleton(); let fIns = new TransparentSingleton();  console.log(eIns === fIns); 

这种方法虽然满足了我们的要求,但是这里存在一个问题,就是内部的TransparentSingleton的这对象,成为了一个私有对象,我们在外面无法访问到

代理版单例模式

var CreateDom = function(html){   this.html = html;   this.init(); }  CreateDom.prototype.init = function(){   console.log(this.html); }  var ProxyCreateDom = (function(){   let instance = null;   return function(html){     if(instance === null){       instance = new CreateDom(html);     }     return instance;   } }())  let hIns = new ProxyCreateDom("测试"); let gIns = new ProxyCreateDom("前端"); console.log(hIns === gIns, hIns.html, gIns.html)  

这里我们将对象提了出来了,通过ProxyCreateDom去创建一个关于CreateDom的单例,但是这个版本是比较有限的,我们可以看到这个代理单例并不是一个可复用的,代码很可能会翻倍。并且不管我们需不要单例,其实ProxyCreateDom里的instance就创建了。并且这个是属于传统面向对象语言的,在JavaScript这个没有类的语言中,这样创建意义并不大

惰性单例模式通用版本

let getSingleton = function(func) {    let result = null;   return function(){      return result || (result = func.apply(this, arguments));   } }  function createLoginLayer(){   var div = document.createElement("div");   div.innerHTML = "我是登录浮窗";   div.style.display = "none";   document.body.appendChild(div);   return div; }  /**  * 测试代码   */ let createSingleLoginLayer = getSingleton(createLoginLayer);  // 添加一个登陆浮窗 document.getElementById("loginTest").onclick = function(){   var loginLayer = createSingleLoginLayer();   loginLayer.style.display = "block" } // 创建一个iframe的单例 var createSingleIfame = getSingleton(function () {   var iframe = document.createElement("iframe");   document.body.appendChild(iframe);   return iframe; }) // 创建一个iframe,并将src属性设置为百度 document.getElementById("loginBtn").onclick = function(){   var loginLayer = createSingleIfame();   loginLayer.src = "http://baidu,com"; } // 将浮窗单例隐藏 document.getElementById("closeLoginBtn").onclick = function(){   var loginLayer = createSingleLoginLayer();   loginLayer.style.display = "none" } // 改变iframe的src属性 document.getElementById("changeUrlBtn").onclick = function(){   var loginLayer = createSingleIfame();   loginLayer.src = "http://127.0.0.1:5500/index.html"; }