内容简介:单例模式的定义为:简单来说,单例模式就是把一堆代码,放入到一个逻辑单元里面,可以通过单一的变量来访问。在我们最开始的写法中。我们通常会这样写:
什么是单例模式?
单例模式的定义为: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
简单来说,单例模式就是把一堆代码,放入到一个逻辑单元里面,可以通过单一的变量来访问。 最大的好处就是封装代码,减少全局变量 。
为什么要使用单例模式?
在我们最开始的写法中。我们通常会这样写:
var btn = document.querySelector('#btn')
btn.onclick = function() {
render()
}
function render() {
console.log('render')
}复制代码
那么上面的代码有什么问题呢?
最主要的就是 全局变量多,难以维护 。
现在我们开始改进:
我们先把这一堆代码整合到一个对象里面,作为他的属性和方法,只保留一个全局变量。通过预留的入口启动。
var app = {
btn: document.querySelector('#btn'),
init: function() {
this.bind()
},
bind: function() {
var _this = this
this.btn.onclick = function() {
_this.render()
}
},
render() {
console.log('render jirengu.com')
}
}
app.init()复制代码
虽然全局变量可以访问了,但是还是有一个缺点,app里面的属性和方法还是暴露了出来,可以直接用app访问。那我们接下来 使用闭包来将部分变量和方法隐藏起来。
var app = (function(){
var btn = document.querySelector('#btn')
function bind() {
btn.onclick = function() {
render()
}
}
function render() {
console.log('render jirengu.com')
}
return {
init: function() {
bind()
}
}
})()
app.init()复制代码
这种特殊的单例模式也叫 模块模式(module pattern)。
那么还有没有改进的方法呢?当然还有, 那就是在我们需要的时候在去创建,而不是立即创建实例 。代码如下:
var Singleton = (function(){
var instance
function createInstance() {
var btn = document.querySelector('#btn')
function bind() {
btn.onclick = function() {
render()
}
}
function render() {
console.log('render jirengu.com')
}
return {
init: function() {
bind()
}
}
}
return {
getInstance: function() {
if(!instance) {
instance = createInstance()
}
return instance
}
}
})()
var app = Singleton.getInstance()
app.init()
复制代码
单例模式的应用场景
当我们访问一个网站的时候,比如访问以前的wepQQ(老版本),当我们点击时候,会有一个弹出层,来让我们去登陆。如下图:
那么,这个唯一的窗口要如何创建呢?
由于我们知道只有当点击登陆按钮的时候,弹层才会出现,所以,我们可以在点击按钮后,惰性的创建一个div弹层。所以js代码如下:
var createLoginLayer = function(){
var 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';
};复制代码
可是这样的实现方法有一个缺点就是, 当我们每次点击登陆按钮时,都会创建一个新的DIV ,当我们点击关闭按钮时候,这个浮层又会消失。这样频繁的触发DOM操作, 创建和删除节点明显是不合理的,也是不必要的。
那么我们是否可以 设置一个变量来判断是否已经创建过浮层 呢?改进后代码如下:
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';
};复制代码
这样便实现了只创建一个浮层需求。
可是上面的代码还有一个问题: 假如我还有其他的地方要创建单一的浮层,那么,我们要几乎将代码原封不动的写一遍,然后实现这个需求。
那么,我们需要把创建一个div和其他的iframe的公共部分给抽离出来: 用一个变量来标志是否创建过对象,如果是,则在下次直接返回这个已经创建好的对象 。
var obj;
if (!obj){
obj = {};
}复制代码
那么我们将这些方法抽离出来,这些逻辑被封装在 getSingle 函数内部,创建对象的方法 fn 被当成参数动态传入 getSingle 函数,代码如下:
function getSingle(fn){
var result;
return result || (result = fn.call(this,arguments));
}复制代码
我们抽离代码后,便可以将创建的逻辑单独拿出来,放入getSingle,我们用result来保存fn的值,由于闭包,所以result永远不回被撤销。
所以代码可以如下所示:
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';
};
复制代码
总结
首先单例模式的核心是: 确保只有一个实例,并提供全局访问。
单例模式是一个简单而且使用的模式,而且惰性的单例模式,是我们可以完成需要的时候再去请求的功能,并且只创建唯一一个。
用好单例模型可以减少DOM的重复渲染,提高浏览器运行的效率。
参考文献
JavaScript设计模式与开发实践
以上所述就是小编给大家介绍的《javascript设计模式之单例模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 设计模式-享元设计模式
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
图片转BASE64编码
在线图片转Base64编码工具
HSV CMYK 转换工具
HSV CMYK互换工具