javascript设计模式之单例模式

栏目: 后端 · 发布时间: 5年前

内容简介:单例模式的定义为:简单来说,单例模式就是把一堆代码,放入到一个逻辑单元里面,可以通过单一的变量来访问。在我们最开始的写法中。我们通常会这样写:

什么是单例模式?

单例模式的定义为: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。

简单来说,单例模式就是把一堆代码,放入到一个逻辑单元里面,可以通过单一的变量来访问。 最大的好处就是封装代码,减少全局变量

为什么要使用单例模式?

在我们最开始的写法中。我们通常会这样写:

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(老版本),当我们点击时候,会有一个弹出层,来让我们去登陆。如下图:

javascript设计模式之单例模式

那么,这个唯一的窗口要如何创建呢?

由于我们知道只有当点击登陆按钮的时候,弹层才会出现,所以,我们可以在点击按钮后,惰性的创建一个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设计模式之单例模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective JavaScript

Effective JavaScript

赫尔曼 (David Herman) / 黄博文、喻杨 / 机械工业出版社 / 2014-1-1 / CNY 49.00

Effective 系列丛书经典著作,亚马逊五星级畅销书,Ecma 的JavaScript 标准化委员会著名专家撰写,JavaScript 语言之父、Mozilla CTO —— Brendan Eich 作序鼎力推荐!作者凭借多年标准化委员会工作和实践经验,深刻辨析JavaScript 的内部运作机制、特性、陷阱和编程最佳实践,将它们高度浓缩为极具实践指导意义的 68 条精华建议。 本书共......一起来看看 《Effective JavaScript》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具