专栏首页胡哥有话说JavaScript设计模式——单体模式

JavaScript设计模式——单体模式

一、单体模式(Singleton Pattern)

1.概念介绍

单体模式(Singleton Pattern)的思想在于保证一个特定类仅有一个实例,即不管使用这个类创建多少个新对象,都会得到与第一次创建的对象完全相同

它让我们能将代码组织成一个逻辑单元,并可以通过单一变量进行访问。

单体模式有以下优点:

  • 用来划分命名空间,减少全局变量数量。
  • 使代码组织的更一致,提高代码阅读性和维护性。
  • 只能被实例化一次。

但在JavaScript中没有类,只有对象。当我们创建一个新对象,它都是个新的单体,因为JavaScript中永远不会有完全相等的对象,除非它们是同一个对象。 因此,我们每次使用对象字面量创建对象的时候,实际上就是在创建一个单例

let a1 = { name : 'leo' };
let a2 = { name : 'leo' };
a1 === a2;  // false
a1 == a2;   // false

这里需要注意,单体模式有个条件,是该对象能被实例化,比如下面这样就不是单体模式,因为它不能被实例化:

let a1 = {
    b1: 1, b2: 2,
    m1: function(){
        return this.b1;
    },
    m2: function(){
        return this.b2;
    }
}
new a1();  // Uncaught TypeError: a1 is not a constructor

下面展示一个单体模式的基本结构:

let Singleton = function (name){
    this.name = name;
    this.obj = null;
}
Singleton.prototype.getName = function(){
    return this.name;
}
function getObj(name){
    return this.obj || (this.obj = new Singleton(name));
}
let g1 = getObj('leo');
let g2 = getObj('pingan');
g1 === g2;    // true
g1 == g2;     // true
g1.getName(); // 'leo'
g2.getName(); // 'leo'

从这里可以看出,单体模式只能实例化一次,后面再调用的话,都是使用第一次实例化的结果。

2.应用场景

单例模式只允许实例化一次,能提高对象访问速度并且节约内存,通常被用于下面场景:

  • 需要频繁创建再销毁的对象,或频繁使用的对象:如:弹窗,文件;
  • 常用的工具类对象;
  • 常用的资源消耗大的对象;

3.实现弹框案例

这里我们要用单体模式,创建一个弹框,大概需要实现:元素值创建一次,使用的时候直接调用。 因此我们这么做:

let create = (() => {
    let div;
    return () => {
        if(!div){
            div = document.createElement('div');
            div.innderHTML = '我是leo创建的弹框';
            div.style.display = 'none';
            div.setAttribute("id", "leo");
            document.body.appendChild(div);
        }
        return div;
    }
})();
// 触发事件
document.getElementById('otherBtn').onclick = () => {
    let first = create();
    first.style.display = 'block';
}

4.使用new操作符

由于JavaScript中没有类,但JavaScript有 new语法来用构造函数创建对象,并可以使用这种方法实现单体模式。 当使用同一个构造函数以 new操作符创建多个对象,获得的是指向完全相同的对象的新指针。

通常我们使用 new操作符创建单体模式的三种选择,让构造函数总返回最初的对象:

  • 使用全局对象来存储该实例(不推荐,容易全局污染)。
  • 使用静态属性存储该实例,无法保证该静态属性的私有性。
function Leo(name){
    if(typeof Leo.obj === 'object'){
        return Leo.obj;
    }
    this.name = name;
    Leo.obj = this;
    return this;
}
let a1 = new Leo('leo');
let a2 = new Leo('pingan');
a1 === a2 ; // true
a1 ==  a2 ; // true

唯一的缺点就是 obj属性是公开的,容易被修改。

  • 使用闭包将该实例包裹,保证实例是私有性并不会被外界修改。

我们这通过重写上面的方法,加入闭包:

function Leo(name){
    let obj;
    this.name = name;
    obj = this;       // 1.存储第一次创建的对象
    Leo = function(){ // 2.修改原来的构造函数
        return obj;
    }
}
let a1 = new Leo('leo');
let a2 = new Leo('pingan');
a1 === a2 ; // true
a1 ==  a2 ; // true

当我们第一次调用构造函数,像往常一样返回this,而后面再调用的话,都将重写构造函数,并访问私有变量 obj并返回。

本文分享自微信公众号 - 胡哥有话说(hugeyouhuashuo)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-01

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 重读《学习JavaScript数据结构与算法-第三版》-第2章 ECMAScript与TypeScript概述

    洛伊安妮·格罗纳女士所著的《学习JavaScript数据结构与算法》第三版于2019年的5月份再次刊印发行,新版内容契合当下,实为JavaScript开发人员的...

    胡哥有话说
  • html5手机网站需要加的那些meta/link标签,html5 meta全解

    <meta name="viewport" content=""> 说明:屏幕的缩放

    胡哥有话说
  • 重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈

    本章是重读《学习JavaScript数据结构与算法-第三版》的系列文章,本章为各位小伙伴分享数据结构-栈的故事,请让胡哥带你走进栈的世界

    胡哥有话说
  • ES6新特性以及一些规范

    ` class goodStudent extends Student { sayAge() { console.log(this.age) } } ...

    嘿嘿嘿
  • python下以api形式调用tesseract识别图片验证码

    之前在博文中介绍在python中如何调用tesseract ocr引擎,当时主要介绍了shell模式,shell模式需要安装tesseract程序,并且效率相对...

    黯然销魂掌
  • Swift3.0 - 镜像

    酷走天涯
  • 字符串的排列

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    喜欢ctrl的cxk
  • double浮点数运算为啥会丢失精度?

    前言:在工作中,谈到有小数点的加减乘除都会想到用BigDecimal来解决,但是有很多人对于double或者float为啥会丢失精度一脸茫然。还有BigDeci...

    王念博客
  • java面试官:Double为什么会丢失精度?解决方法?答出给1万月薪

    在工作中,谈到有小数点的加减乘除都会想到用BigDecimal来解决,但是有很多人对于double或者float为啥会丢失精度一脸茫然。还有BigDecimal...

    IT大咖说
  • TRTC学习之旅(一)--多人聊天室web篇(官方demo)

    大家好,我是刚入坑TRTC的小菜鸡,黑圆圈云豆。因为我的主要技术方向是web,所以我就从基于web开发的TRTC demo进行学习和知识分享。

    黑眼圈云豆

扫码关注云+社区

领取腾讯云代金券