单例模式
定义
单例模式的定义是: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
一个最简单的单例模式
最简单的单例模式非常容易实现,只需要一个变量去储存new
出来的对象,下次再去这个对象时,只需要判断变量里是否有之前创建好的对象,如果有就直接返回,没有再重新new
一个对象。
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;
};
var b = Singleton.getInstance("sven2");
var a = Singleton.getInstance("sven1");
alert(a === b); // true
JavaScript中的单例模式
前面提到的一种单例模式的实现,更多的是接近传统面向对象语言中的实现,单例对象从“类”中创建而来。
JavaScript
是一个无类的语言。所以不需要生搬单例模式的概念。对象直接用 const a = {}
便能创建
单例模式的核心就是确保只有一个实例,并提供全局访问。
因此,实际上在很多情况下,我们可以直接用全局变量来当做单例模式的实现。 但是,全局变量有很多问题,比如造成命名空间污染。可以用以下方法去解决。
- 使用命名空间。 命名空间不能杜绝全局变量,只能一定程度上减少全局变量。
- 使用闭包封装私有变量 只暴露一些接口,去得到变量。
var user = (function () {
var __name = "sven",
__age = 29;
return {
getUserInfo: function () {
return __name + "-" + __age;
},
};
})();
一个需求中的单例模式实际应用
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";
};
这这块代码中,在点击loginBtn
时会触发函数,创建一个弹窗层的对象,而且用闭包存储了这个节点,下次调用会直接返回之前创建好的节点,无疑是运用了单例模式。
但是这么做,是违反了单一职责原则的,创建和管理单例的逻辑都放在了createLoginLayer
这个对象内部。而后果也显而易见,如果你想要创建一个页面中唯一的iframe
或者是script
去请求跨域数据,都需要把这个函数抄一遍。
因此我们完全可以抽离出来一个单例模式的逻辑,用一个变量来标志是否创建过对象,如果是,则在下次直接返回这个已经创建好的对象。
let obj;
if ( !obj ){
obj = x;
}
将逻辑抽离出来放在getSingle
里,而参数是一个函数,就是上文中的创建登录浮窗的方法。
const getSingle = ( fn ) => {
var result;
return function(){
return result || ( result = fn.apply(this, arguments ) );
}
};
这样一来我们只需要关注自己的方法如何实现,只要使用getSingle
去包裹一下实现的方法,生成的函数,就已经实现了单例模式。
var createLoginLayer = function () {
var div = document.createElement("div");
div.innerHTML = "我是登录浮窗";
div.style.display = "none";
document.body.appendChild(div);
return div;
};
var createSingleLoginLayer = getSingle(createLoginLayer);
document.getElementById("loginBtn").onclick = function () {
var loginLayer = createSingleLoginLayer();
loginLayer.style.display = "block";
};
总结
在实现一个可以运用在项目中的单例模式,需要对闭包以及高阶函数有一定了解,可以最大程度的去解耦,创建对象或者说实现一个方法是我们需要关注的内容,而如何管理单例,是一个通用的方法,完全可以将其抽离出来,两个一结合就是一个完美的单例模式。