- A+
所属分类:Web前端
单例模式
简单的单例模式
通过一个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"; }