内容简介:单例模式的定义为:简单来说,单例模式就是把一堆代码,放入到一个逻辑单元里面,可以通过单一的变量来访问。在我们最开始的写法中。我们通常会这样写:
什么是单例模式?
单例模式的定义为: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
简单来说,单例模式就是把一堆代码,放入到一个逻辑单元里面,可以通过单一的变量来访问。 最大的好处就是封装代码,减少全局变量 。
为什么要使用单例模式?
在我们最开始的写法中。我们通常会这样写:
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设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective JavaScript
赫尔曼 (David Herman) / 黄博文、喻杨 / 机械工业出版社 / 2014-1-1 / CNY 49.00
Effective 系列丛书经典著作,亚马逊五星级畅销书,Ecma 的JavaScript 标准化委员会著名专家撰写,JavaScript 语言之父、Mozilla CTO —— Brendan Eich 作序鼎力推荐!作者凭借多年标准化委员会工作和实践经验,深刻辨析JavaScript 的内部运作机制、特性、陷阱和编程最佳实践,将它们高度浓缩为极具实践指导意义的 68 条精华建议。 本书共......一起来看看 《Effective JavaScript》 这本书的介绍吧!