专栏首页前端学习归纳总结JavaScript设计模式 单例模式

JavaScript设计模式 单例模式

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

先看一下,在Js中使用传统面向对象的单例模式。

面向对象的单例模式,是通过new关键字来实例化我们想要的对象,并将其赋值给instance。

通过使用变量instance来判断是否已经实例化,这里将创建一个div和保证只有一个对象的两个功能分割开来实现,对于代码的可维护性提高了很多。假设我们有一天,需要创建多个div,直接利用创建div的类就可以了,而不需要额外的修改。

代理类是属于代理模式中的应用,会在代理模式中详细学习。

var CreateDiv = function(html){
        this.html = html;
        this.init();
    };
    CreateDiv.prototype.init = function(){
        var div = document.createElement('div');
        div.innerHTML = this.html;
        document.body.appendChild(div);
    };
    //引入代理类proxySingletonCreateDiv
    var proxySingletonCreateDiv = (function(){
        var instance;
        return function(html){
            if(!instance)  instance = new CreateDiv(html)
            return instance;
        }
    })();

    //测试
    var a = new proxySingletonCreateDiv('svent1');
    var b = new proxySingletonCreateDiv('svent2');
    console.log(a === b);  //true

我们知道单例模式的核心是确保只有一个实例,并提供全局访问。在JS的世界中,是不存在实质的可使用的类的,上面的只是模仿面向对象语言的实现方法,但Js有全局变量的特性,虽然它不是单例模式,但通常可以把全局变量当作单例模式来使用,如上面的例子可以修改为如下:

将instance作为全局变量同时也作为唯一的创建的div。

var CreateDiv = function(html){
        this.html = html;
        this.init();
    };
    CreateDiv.prototype.init = function(){
        var div = document.createElement('div');
        div.innerHTML = this.html;
        document.body.appendChild(div);
    };
    var instance = new CreateDiv('svent1');

    //测试
    var a = instance;
    var b = instance;
    console.log(a === b);  //true

惰性单例

惰性单例指的是在需要的时候才创建对象实例。

在实际开发中,惰性单例的技术非常有用,正如当我们在web.qq.com即网页版QQ中,点击左边的导航里的QQ头像时,会弹出一个登录框,很明显这个登录框是唯一的,不可能同时出现,并且我们可以在用户点击的时候才来生成该登录框,这样当用户仅仅是浏览页面而不需要登陆时,可以节省一些DOM节点。

在上面的面向对象开发单例模式的例子中,采用的就是懒惰单例,当用户第一次new代理类时,才开始实例化CreateDiv类。

首先来写一个登录框例子:

//创建登录框和判断单例
    var createLoginLayer = (function(){
        var div;
        return function(){
            if(!div){
                div  = document.createElement('div');
                ...
                ...
            };
            return div;
        }
    })();
    //点击事件
    document.getElementById('loginBtn').onclick = function(){
        var loginLayer = createLoginLayer();
        ...
    }

上面这个例子实际上还是有问题的,它把创建对象和管理单例的逻辑都放在一起,如果我们下次需要创建页面中唯一的iframe或其他标签,那么就得把上面的代码照抄一遍。

//创建登录框和判断单例
    var createIframe = (function(){
        var iframe;
        return function(){
            if(!iframe){
                iframe  = document.createElement('iframe');
                ...
                ...
            };
            return iframe;
        }
    })();
    //点击事件
    document.getElementById('loginBtn').onclick = function(){
        var loginLayer = createIframe();
        ...
    }

根据设计模式的单一职责原则,我们需要把不变的部分隔离出来,如管理单例完成可以抽象出来,用一个变量来标志是否创建过对象,如果是,则在下次直接返回该对象。

因为result变量在闭包中,所以永远不会被销毁。

var getSingle = function(fn){
        var result;
        return function(){
            return result || (result = fn.apply(this,arguments));
        }
    }

最后的实际代码:

在这个实验中,我们把创建对象的职责和管理单例的职责分别放在两个方法里,这两个方法可以独立变化而互不影响,而当他们链接在一起,就完成了创建唯一实例对象的功能。

var getSingle = function(fn){
        var result;
        return function(){
            return result || (result = fn.apply(this,arguments));
        }
    };
    var createDiv = function(){
        div  = document.createElement('div');
        ...
        ...
        return div;
    }
    var createLoginLayer = getSingle(createDiv);

    //点击事件
    document.getElementById('loginBtn').onclick = function(){
        var loginLayer = createLoginLayer();
        ...
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JavaScript设计模式 策略模式

    在现实中,我们到达一个地方,通常可以选择不同的方式,例如自行车,火车,汽车,飞机等。

    菜的黑人牙膏
  • Zepto整体概况

    菜的黑人牙膏
  • Js-函数式编程 前言什么是函数式编程为什么Js支持FP纯函数柯里化组合 compose范畴学functorMonadApplicative FunctorFunctor\Monad\Applic

    JavaScript是一门多范式语言,即可使用OOP(面向对象),也可以使用FP(函数式),由于笔者最近在学习React相关的技术栈,想进一步深入了解其思想,所...

    菜的黑人牙膏
  • 惰性单例分析与学习

    本文基于你已经知道单例模式的要点,本文内容借鉴于《javascript设计模式与开发实践》这本书,做出了整理和一些思考。

    RobinsonZhang
  • JavaScript设计模式学习(四)单件(Singleton Pattern)

    单件是JavaScript中最基本、最有用的设计模式,而你今后也会经常的使用这个模式。通过单件,我们可以把统一到一个逻辑单元中并且提供一个唯一的入口,这就保证你...

    大江小浪
  • 编写自己的代码库(javascript常用实例的实现与封装)

    因为公司最近项目比较忙,没那么多空余的事件写文章了,所以这篇文章晚了几天发布。但是这也没什么关系,不过该来的,总是会来的。 好了,其他的不多说的,大家在开发的时...

    守候i
  • 编写自己的代码库(javascript常用实例的实现与封装--续)

    这个系列的上一篇文章(编写自己的代码库(javascript常用实例的实现与封装))总结了34个常见的操作。但是在开发中,常见的实例又何止这么多个,经过这些日子...

    守候i
  • 原生态纯JavaScript 100大技巧大收集---你值得拥有(1--50)

    21、原生JavaScript中有insertBefore方法,可惜却没有insertAfter方法?用如下函数实现

    用户1272076
  • 脚本错误量极致优化-让脚本错误一目了然

    JS 代码压缩后,定位具体出错代码困难?本篇将结合示例,通过多种解决方案逐一分析,让脚本错误 一目了然。

    腾讯AlloyTeam
  • html5打开摄像头

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta content="text/html...

    李海彬

扫码关注云+社区

领取腾讯云代金券