单例模式
定义: 保证一个类只有一个实例,并提供一个访问它的全局访问点。
var single = function(name){ this.name = name; this.instance = null;}single.prototype.getName = function(){ alert(this.name)}single.getInstance = function(name){ if(!this.instance){ this.instance = new single(name) } return this.instance}var a = new single.getInstance('ffff');var a2 = new single.getInstance('zzzz');// a == a2 => true
或者
var single = function(name){ this.name = name;}single.prototype.getName = function(){ console.log(this.name)}single.getInstance = (function(){ var instance = null; return function(name){ if(!instance){ instance = new single(name) } return isntance }})()
使用single类时,我们必须知道它是一个单例类,跟以往new出一个新对象的方式不同,这里要使用single.getInstance来获取对象。
透明的单例
var createDiv = (function(){ var instance = null; var createDiv = function(html){ if(instance) return instance this.html = html; this.init() return instance = this; } createDiv.prototype.init = function(){ var div = document.createElement('div') div.innerHTML = this.html; document.body.appendChild(div) } return createDiv})()
这个透明类的单例,我们使用了自执行函数和闭包,并且让这个匿名函数返回真正的single构造方法,增加了代码的复杂度,读起来需要一定的时间来理解
构造函数的作用,实际上做了两件事,创建对象和执行初始化init方法,第二保证了只有一个对象
用代理来实现单例模式
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 proxySingle = (function(){ var instance; return function(html){ if(!instance){ instance = new createDiv(html) } return instance }})()
通过代理模式完成的代码,我把管理单例的逻辑移到了proxySingle里,这样createDiv就变成了一个普通的类
这个例子是缓存代理的应用之一。
惰性单例
惰性单例指的是在需要的时候才创建对象实例。
这种技术在实际开发中非常有用。
在网站首页,有个登陆按钮,点击登录 弹出登录框。很明显这个登录框在页面中是唯一的,不会也不可能出现两个登陆框。
首先我们可以页面加载完成时就加载这个登录框,此时这个登录框出于隐藏状态。
但是如果我进入页面只是想看看,不想进行一些需要登陆的业务操作,此时登陆框的dom节点存在是没有意义的,是一种浪费。此时,单例模式就更实用了//dom//jsvar createLogin = (function(){ var div; return function(){ if(!div){ div= document.createElement('div'); div.innerHTML = "i'm login form"; div.display.style="none"; document.body.appendChild(div); return div } } })()document.getElementById('login').onClick = function(){ var loginDom = createLogin(); loginDom.display.style ='block'}
通用惰性单例
我们参考上边的代码,如果需要在创建一个iframe单例,或者其他标签,难道需要把上边的函数重新copy一份修改.单例的逻辑可以抽象出来,并且始终不变的,可以理解为
var instance;if(!instance){ instance = xxx操作}return instance
我们将管理单例的逻辑抽象封装起来getInstance
var getInstance = function(fn){ var instance; return function(){ return instance || (result = fn.apply(this,arguments)) }}//创建登陆var createLogin = getInstance(function(){ var div = document.createElement('div'); div.innerHTML = '我是的登陆'; div.style.display = 'none'; document.body.appenChild(div); return div})//$('#login').on('click',function(){ var login = createLogin(); $(login).show()})//创建scriptvar createScript = getInstance(function(){ var script = document.createElement('script'); document.appendChild(script) return script})$('#loadScript').on('click',function(){ var script = createScript(); $(script).show();})
将创建实例对象的职责和管理单例的职责分别放置在两个方法里,这两个方法独立,不会互相影响。