• JavaScript设计模式及代码实现——单例模式


    单例模式

    singleton

    1 定义#

    保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    2 应用时机#

    1. 当一个类的实例被频繁使用,如果重复创建这个实例,会无端消耗资源。比如 dialog 弹窗会被全局重复使用
    2. 业务功能本身决定了全局只能有唯一的实例。比如 redux 管理的数据,只能有唯一的一份

    3 应用场景#

    1. 对于前端应用的许多基本组件:比如 dialog、message等等,会被全局频繁使用,就应该维护一个全局唯一的实例,避免重复创建带来不必要的资源消耗。业务组件也同理:比如购物车组件、登录弹窗组件等
    2. 对于一些通用的工具库,经常会使用单例模式。比如我们通常会创建一个全局唯一的 axios 实例来发起网络请求
    3. 对于 redux、vuex 等状态管理库,都采用全局唯一的 store 来存储应用状态数据

    等等 ……

    4 代码实现#

    4.1 全局变量和命名空间#

    根据单例模式的定义

    // 维护类 A 的唯一实例
    class A {}
    window.a = new A(); // 或 global.a = new A(); 浏览器用 window

    这种方法存在很明显的缺陷,因为同一项目的所有程序员都可以定义全局的变量 a,很容易造成全局污染。

    解决办法是设定一个自己的命名空间来和其他人区分

    // 比如我设定自己的命名空间 JiMing
    window.JiMing = {
    a: new A()
    }

    如果使用 TypeScript ,可以使用关键字 namespace

    namespace JiMing {
    export const a = new A();
    }

    4.2 惰性单例#

    上述实现中,我们直接在全局创建了类 A 的单一实例,无论其是否被使用,这在某些场景会造成资源浪费。有时我们希望在用到的时候再创建实例

    如下代码利用立即执行函数和闭包来得到 A 的单例获取函数:getSingletonOfA

    class A {}
    const getSingletonOfA = (() => {
    let instance;
    return () => {
    return (instance ??= new A());
    };
    })();

    只有在调用getSingletonOfA才会创建 A 的实例,并且会在闭包中将其储存在 instance 中,重复调用getSingletonOfA会获取相同的实例

    const a1 = getSingletonOfA();
    const a2 = getSingletonOfA();
    console.log(a1 === a2); // true

    上述方法能够满足单例模式,但是不够通用,改造如下

    const createSingletonUtil = (className) => {
    let instance;
    return () => {
    return (instance ??= new className());
    };
    };

    我们封装一个工具函数createSingletonUtil,调用该函数后可以获得任意类的“单例获取函数”

    const getSingletonOfA = createSingletonUtil(A);
    const a3 = getSingletonOfA();
    const a4 = getSingletonOfA();
    console.log(a3 === a4); // true

    createSingletonUtil 的 TypeScript 实现如下:

    class A {}
    const createSingletonUtil = (className: new () => T) => {
    let instance: T;
    return () => {
    return (instance ??= new className());
    };
    };
    const getSingletonOfA = createSingletonUtil(A);
    const a1 = getSingletonOfA();
    const a2 = getSingletonOfA();
    console.log(a1 === a2);

    当然惰性单例也有缺点,对于某些类,如果创建实例需要较长时间,这时在用到的时候再创建恐怕来不及,可能会产生其他副作用,比如造成页面卡顿。在此场景下,在应用初始化时就创建其实例或许会有更好的用户体验

    上述两种方法根据不同的业务场景择一使用即可

    公众号【今天也要写bug】(op-bot)提问答疑

  • 相关阅读:
    GitHub详解:代码托管与协作开发平台
    数据结构学习-迷宫问题
    A sequence-to-sequence approach for document-level relation extraction
    从菜鸟到大师:编程必须遵循的三个基本原则
    基于最近电平逼近的开环MMC逆变器Simulink仿真模型
    推出多项云安全服务和功能,亚马逊云科技 re:Inforce 全球大会来袭,为企业创新护航!
    promise及异步编程async await
    WiFi 四次握手&Omnipeek抓包
    【笔试强训选择题】Day42.习题(错题)解析
    json schema实际运用
  • 原文地址:https://www.cnblogs.com/bidong/p/16635694.html