单例模式的定义
定义
单例模式又称为单体模式,是只允许实例化一次的对象类。
单例模式基本结构
从广义的定义来说,单例模式只是一个用来划分命名空间并将一系列相关方法和属性组织在一起的对象,并且只能实例化一次。最简单的单例就是一个对象字面量。
var single = {
name:'Yimi',
getName() {return this.name;}
.....
}
单例模式的实现
实现单例模式的核心就是确保只有一个实例并提供全局访问。例如实现一个创建div的单例类。
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;
})()
var a = new createDiv('a');
var b = new createDiv('b');
console.log(a === b); //true
优雅的单例模式
上面的例子实现了一个单例模式,在页面创建一个唯一的div节点。createDiv的构造函数实际上完成了两件事情,一是负责创建div节点,二是保证只有一个对象,这样不符合“单一职责原则”,当我们要让这个类不再是单例模式或者创建其他唯一节点(如iframe,script等)时,就需要改写该方法。
基于此,我们可以通过引入代理类来写出更为通用的单例模式。createDiv只保留创建节点的功能,同时新增一个proxyCreateDOM的类来实现单例模式。
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 proxyCreateDOM = (function(){
var instance = null;
return function(html) {
if(instance) {return instance;}
instance = new createDiv(html);
return instance;
}
})()
惰性单例模式
惰性单例是指在需要的时候才创建对象。
上面的proxyCreateDOM方法但单例对象createDiv是在脚本加载时被创建(new
)出来的,而惰性单例则是在需要使用它的时候再实例化。一般会借助于一个静态方法来实现。例如针对proxyCreateDOM方法进行改造,返回一个getInstance的公用方法,在该方法中实现单例类实例化的控制。此时,instance对象会在我们调用proxyCreateDOMLazy.getInstance
方法时才创建。
var proxyCreateDOMLazy = (function(){
var instance = null;
function createDom(html) {
instance = new createDiv(html);
return instance;
}
return {
getInstance:function(html) {
if(instance) {return instance;}
instance = createDom(html);
return instance;
}
}
})()
var login = proxyCreateDOMLazy.getInstance('login')
惰性单例最常用于必须加载大量数据的单体,对于资源密集型的或者配置开销较大的单体,更适合于将其实例化推迟到需要使用它的时候。
1.惰性单例是指在需要使用的时候去new 或者去调用静态方法创建实例
2.创建弹窗或者那些只要执行一次就可以全局使用的实例都可以用单例
单例模式的应用
命名空间
命名空间,即namespace,是用来解决在开发过程中使用重复变量名会导致代码冲突情况的方法,例如我们使用过的jQuery库,就为我们提供了一个命名空间jQuery。
管理代码库的模块
单例模式除了定义命名空间之外,还可以用来管理代码库的各个模块。
我们可以创建一个小型的代码库,例如我们有一个Util库,它包含一些公用方法,那么就可以定义一个单独的代码库。
var Util = {
Tool : {
getTimeStamp() {...},
getTraceId() {...}
},
Ajax : {
get() {...},
post() {...}
}
}
创建静态变量
单例模式还有一个功能就是可以管理静态变量。静态变量是指具有只能访问不能修改并且创建后就能使用特点的变量。在JavaScript中,可以通过定义一个可访问的变量可以通过定义全局变量的方式或者在函数内部定义变量并通过闭包的方式提供访问的方式,但是基于静态变量不能修改的特性,我们需要采用后者来创建变量。同时,为实现创建后就能使用特点,我们可以通过立即执行函数来执行一次。
var single = (function(){
var MAX_VAL = '1200';
return {
getMaxVal() {
return MAX_VAL
}
}
})()
console.log(single.getMaxVal())
另一个创建静态变量的方法是在单例对象内使用带下划线的变量名来定义方法或属性,例如_script
。但这种方法不能保证这些私有属性和方法不会在单体对象之外被访问到。