单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
当我们点击登陆按钮时,页面会出现登陆浮窗,无论点击多少次按钮,这个浮窗只会被创建一次,那么它就适合用单例模式来创建。
1 JavaScript中的单例模式
我们经常把全局变量当成单例模式使用,但它会造成命名空间污染。可以用以下方法降低全局变量带来的命名污染。
1 .1使用命名空间
最简单的方法是用字面对象量:
var namespace = { a: function{ alert(1); }, b: function{ alert(1); } }
还可以动态创建命名空间:
var MyApp = {}; MyApp.namespace = function( name ) { var part = name.split('.'); var current = MyApp; for(var i in part) { if(! current[ part[ i ] ]) { current[part[ i ]] = {}; } current = current[ part[ i ] ] } } MyApp.namespace( 'event' ); MyApp.namespace( 'dom.style' ); //上述代码等于 var MyApp = { event: {}, dom: { style: {} } }
1 .2使用闭包封装私有变量
把变量来封装在闭包内,只暴露一些接口与外界通信:
var user = (function() { var _name = 'sun', _age = 9; return { getUserInfo: function() { return _name = '-' + _age } } })()
2 惰性单例
惰性单例是指在需要时才创建对象实例。
这是一个可用的惰性单例,但它违反单一职责原则,创建对象和管理单例的逻辑都放在createLoginLayer中。要创建其他标签时,还要把函数几乎重写一次。
var createLoginLayer = (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( 'loginBtn' ).onclick = function(){ var loginLayer = createLoginLayer(); loginLayer.style.display = 'block'; };
把管理单例的逻辑抽出,封装在函数内部,创建对象的方法fn作为参数动态传入。
将用来创建浮窗的方法以fn参数传入getSingle,让getSingle返回一个新函数,并用result保存fn的结果,result因为保存在闭包不会被销毁。如果result已经被赋值,返回这个值。
var getSingle = function( fn ) { var result; return function(){ return result || fn.apply(this, arguments); } }
var createLoginLayer = function(){ var div = document.createElement( 'div' ); div.innerHTML = '我是登录浮窗'; div.style.display = 'none'; document.body.appendChild( div ); return div; }; var createSingleLoginLayver = getSingle( createLoginLayer ); document.getElementById( 'loginBtn' ).onclick = function(){ var loginLayer = createSingleLoginLayer(); loginLayer.style.display = 'block'; };