JavaScript设计模式---单例模式详解【四种基本形式】
单例模式是一种常用的设计模式,它是指在整个应用程序中只需要实例化一次的类。在JavaScript中,单例模式具有着特殊的意义。因为JavaScript是一种无状态语言,每次请求网页都会加载一次JavaScript文件,如果我们没使用单例模式来管理,可能会在内存中生成多个对象实例,造成资源的浪费,而且数据容易混乱。
普通形式
普通的单例模式大概长这样:
var Singleton = function(name) {
this.name = name;
this.instance = null; // 标示属性
};
Singleton.prototype.getName = function() {
console.log(this.name);
};
Singleton.getInstance = function(name) { // 静态方法
if (!this.instance) { // 如果已经存在实例直接返回
this.instance = new Singleton(name);
}
return this.instance;
}
// 利用静态方法创建实例
var s1 = Singleton.getInstance('张三');
var s2 = Singleton.getInstance('李四');
s1.getName(); // 张三
s2.getName(); // 张三
console.log(s1 === s2); // true
以上代码中,我们创建了一个Singleton
单例类,并为其添加了getName
方法和静态方法getInstance
。
静态方法是指定义在类上的方法(该方法并不能在实例上调用,你可以粗略的把它理解为类级别的方法)。它可以方便我们直接调用这个方法,而不需要先实例化一个对应的对象,例如在以上示例中我们可以这样调用Singleton.getInstance('张三')
,当我们需要使用这个类时,我们直接使用Singleton.getInstance
方法即可。如果这个类的实例不存在,那么就创建一个实例,并把它存储在instance
中;下次请求实例时,直接返回已经创建的实例对象,该示例中是通过一个标示属性instance
来标记这个类是否被实例化(如果已经有实例,就不会再次创建)。
在以上示例中,我们创建了两个不同的实例s1
、s2
,但是它们的name
属性值都是“张三”。通过console.log(s1 === s2)
我们可以看到它们的值为true
,说明s1
和s2
都是指向同一个对象的引用,也就是说这一整个过程中只创建了一个实例。
Javascript的缓存机制形式
除了普通形式,我们还可以将缓存机制来实现单例模式。由于函数也是对象,所以我们可以用闭包来封装私有变量。
var Singleton = function(fn) {
var instance;
return function() {
return instance || (instance = 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 getSingleLoginLayer = Singleton(createLoginLayer); // 单例模式
document.getElementById('loginBtn').onclick = function() {
var loginLayer = getSingleLoginLayer();
loginLayer.style.display = 'block';
}
以上示例中,我们创建了一个闭包函数Singleton
,这个函数将一个函数作为参数fn
传入,然后返回一个内置函数。这个内置函数首先声明了 instance
变量,然后在每次函数被调用时,检查 instance
变量是否有值。如果有值,就返回这个 instance
变量,而不是重新创建一个对象。如果没有,就调用传入 Singleton
函数的这个函数(例如我们在这个示例中传入的 createLoginLayer
)来创建一个对象,并将这个对象赋值给 instance
变量,最后返回这个对象。由于浏览器缓存机制的存在,下次我们点击登录按钮时,不需要再次重复创建这个登录浮窗,而是直接获取前一个浮窗就行了。
惰性单例模式
惰性单例是指在需要的时候才去创建对象实例。
var createLoginLayer = function() {
var div = document.createElement('div');
div.innerHTML = '我是登录浮窗';
div.style.display = 'none';
document.body.appendChild(div);
return div;
};
var createSingleLoginLayer = (function() {
var instance;
return function() {
return instance || (instance = createLoginLayer());
}
})();
document.getElementById('loginBtn').onclick = function() {
var loginLayer = createSingleLoginLayer();
loginLayer.style.display = 'block';
}
以上示例中,我们使用立即执行函数(IIFE)对单例对象进行了包装,并且在返回的函数中对单例对象进行判断,如果单例对象已经存在,则直接返回。如果不存在,则先进行初始化操作。这样就实现了只有在有需要时才对单例的对象进行初始化。
通过以上三种实现方式,我们可以发现单例模式的核心思想:控制实例的数量,节约系统资源。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript设计模式—单例模式详解【四种基本形式】 - Python技术站