单例模式:保证一个类只有一个实例,并提供一个可以访问它的全局访问点。
一种简单、方便的写法就是用一个变量来标识当前类是否已经创建过对象,如果有,则返回已经创建好的对象,否则创建一个新对象,并将其返回。
var Singleton = function(name) {
this.name = name;
this.instance = null;
} Singleton.prototype.getName = function() {
alert(this.name);
} Singleton.getInstance = function(name) {
if (!this.instance) {
this.instance = new Singleton(name);
}
return this.instance
}
但是上述写法有一个问题,那就是使用Singleton这个类的时候,必须参考API文档,否则使用者不知道必须通过getInstance()方法而不是通过new的方式来获取对象,这就是增加了这个类的“不透明”性。
修改上述实现方式,使其变得“透明”些。
var Singleton = (function() {
var instance = null; var Singleton = function(name) {
if (!instance) {
this.name = name;
instance = this;
} return instance;
} Singleton.prototype.getName = function() {
alert(this.name)
} return Singleton;
})()
修改后的Singleton类使用起来和其他的类没有区别,只要new Singleton('name')就可以了,但是上述写法也有一点小问题,那就是在Singleton的构造函数中做了两件事,一是创建对象并初始化name等变量,二是保证了该类只会存在一个对象,违反了设计原则中的“单一职责原则”的概念。如果后续要将Singleton改为非单例类,就必须要修改Singleton的构造函数。
为了使职责分的更加清楚,我们引入代理的方式来实现单例。
var Manager = function(name) {
this.name = name;
} Manager.prototype.getName = function() {
alert(this.name);
} var Singleton = (function() {
var instance;
return function(name) {
if (!instance) {
instance = new Manager(name)
}
return instance
}
})()
通过引入代理类,保证了各个类之间的职责单一。
上述是通过类的方式来创建单例对象,在其他语言中经常会看到这样的写法,如Java,C#等。但是JavaScript其实是一门无类(class-free)的语言,想要一个对象,直接创建就可以了,没有必要先创建类,再通过类创建对象,这样做无异于穿棉衣洗澡。所以说基于“类”的单例在JavaScript中其实并不适用。
在实际项目中经常会用到摸态框,一般来说,一个页面的模态框是唯一的,最常见的实现方式有以下两种方式:
- 在页面加载完成的时候便创建好模态框,当然这个模态框是隐藏的
- 当真正需要显示模态框时再创建
第一种方式简单,但是可能会浪费DOM元素,因为部分用户可能一直用不到这个模态框。第二种方式就需要用到将要学习的惰性单例。
var getSingle = (function() {
var instance;
return function(fn) {
return instance || (instance = fn.apply(this, arguments));
}
})() var createModal = function() {
var div = document.createElement('div');
div.innerHTML = 'modal';
document.body.appendChild(div);
return div;
}
将getSingle方法提取出来,以后不光可以用于createModal,createXhr,createIframe等等都可以与getSingle组合使用。