如何实现一个单例用 JavaScript

Vanessa 大前端的点滴生活 本文由博客端 http://vanessa.b3log.org 主动推送

2020-07-27

描述

单例是一种面向对象的软件设计模式,用来确保给定的类只能被实例化一次,这在很多不同的情况下都非常有用,例如创建在应用程序之间共享的全局对象和组件。虽然 JavaScript 支持面向对象编程,但他并没有提供许多简单的方式来实现这个模式。

说明

Proxy object 虽然某些方面比较超前,但他最容易扩展。Proxy 对象可用于定义所谓的 traps,这些方法允许为某些操作,如属性查找、赋值等行为进行自定义。单例模式规定给定的类只能有一个实例,这意味着最有用的 trap 是 handler.construct(),该 trap 为 new 操作。

由于 handler 本身为一个对象,因此我们可以使用他来存储我们所需类的唯一实例,如果他已实被例化,同时还可以通过 handler.construct()new 操作提供 trap。这样,我们就能为任何我们想要转换为单例的类简单复用的创建一个对象,当然,我们还可以为其他任何我们可能需要的操作提供额外的自定义 trap。

代码

将一个 class 转换为一个单例最基本的方法:

const singletonify = (className) => {
  return new Proxy(className.prototype.constructor, {
    instance: null,
    construct: (target, argumentsList) => {
      if (!this.instance)
        this.instance = new target(...argumentsList);
      return this.instance;
    }
  });
}

这有一个简单的使用示例可以让你更好的理解他的原理:

class MyClass {
  constructor(msg) {
    this.msg = msg;
  }

  printMsg() {
    console.log(this.msg);
  }
}

MySingletonClass = singletonify(MyClass);

const myObj = new MySingletonClass('first');
myObj.printMsg();  // first
const myObj2 = new MySingletonClass('second');
myObj2.printMsg();  // first

总结

在上面的示例中,你可以看到 MySingletonClass 并没有被第二次实例化,这是因为实例已经存在,因此返回实例本身来替代新对象的创建。以上代码虽然只是 singletonify 方法的最小实现,但他能很容易的进行扩展:我们可以进一步修改其行为;我们甚至可以在后续的调用中使用一些传递给构造器的数据来更新他自己的 instance

返回总目录

每天 30 秒系列之 JavaScript 代码

  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    473 引用 • 377 回帖 • 3 关注
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    635 引用 • 1121 回帖 • 766 关注
  • 代码
    410 引用 • 537 回帖 • 5 关注
  • 单例
    6 引用

赞助商 我要投放

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...