[JS] JS单例模式的实现

这篇具有很好参考价值的文章主要介绍了[JS] JS单例模式的实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

JS 单例模式的实现

单例模式简介

单例模式(Singleton Pattern)是最简单的设计模式之一。这种类型的设计模式属于创建型模式,提供了一种创建对象的最佳方式。

特点

  • 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
  • 主要解决:一个全局使用的类频繁地创建与销毁。
  • 何时使用:当您想控制实例数目,节省系统资源的时候。
  • 如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

首先对比一下平时不使用单例模式的情况:

在不适用单例模式的情况下,如下,会得到不同的多个实例:

video.js

class Video{
    constructor() {
        console.log("video created");
    }
}

export { Video };

main.js

import { Video } from "./video.js";

const v1 = new Video();
const v2 = new Video();

console.log(v1 === v2);

控制台输出

方法1:提前构造实例

提前构造一个实例,只向外部暴露该实例的引用,从而实现单例。

但是缺点是需要提前构造实例,而无法做到在需要的时候创建实例。

class Video{
    constructor() {
        console.log("video created");
    }
}

const v = new Video();

export { v };

方法2:构造方法私有化

video.js

class Video{
    private constructor() {
        console.log("video created");
    }

    static _ins = null;
    static getInstance(){
        if(!this._ins){
            this._ins = new Video();
        }
        return this._ins;
    }
}

export { Video };

main.js

import { Video } from "./video.js";

const v1 = Video.getInstance();
const v2 = Video.getInstance();

console.log(v1 === v2);

通过将构造方法私有化,外部无法通过new实例化对象,只能通过静态方法getInstance获取实例。

而在类的内部实现中,使用_ins确保只存在一个实例。

缺点

原生JS不存在private,需要使用TS

JS中,如果剔除private,仅通过getInstance也可以实现单例模式。但是这种方法不严格,无法确保每一个调用者不会使用构造函数创建新的实例。

方法3:通用方法——将任意类转为单例

singleton.js

export function singleton(className){
    let ins;
    return class{
        constructor(...args) {
            if(!ins){
                ins = new className(...args);
            }
            return ins;
        }
    };
}
  • 这个函数接收一个类,进行改造之后返回一个新的类;
  • 使用闭包,存储实例对象ins
  • 新的类的构造函数相当于拦截作用:
    • 如果ins不存在,则将传入的参数转交给原来的类的构造函数,并创建一个实例;
    • 如果ins存在,则直接返回存储在闭包中的实例对象。

video.js

import { singleton } from "./singleton.js";

class Video{
    constructor() {
        console.log("video created");
    }
}

const newVideo = singleton(Video);

export { newVideo as Video };

main.js

import { Video } from "./video.js";

const v1 = new Video();
const v2 = new Video();

console.log(v1 === v2);

控制台输出

观察到这种实现下,构造函数只被调用了一次,并且v1v2指向同一个实例。

缺点

main.js

Video.prototype.play = function(){
    console.log("play");
}

v1.play(); // Uncaught TypeError: v1.play is not a function

在这个案例中,我们试图在Video的原型上添加一个方法,并通过实例对象v1调用,但是v1所处的原型链上并不能找到这个方法。

再回过头来观察singleton.js的实现:

export function singleton(className){
    let ins;
    return class{
        constructor(...args) {
            if(!ins){
                ins = new className(...args);
            }
            return ins;
        }
    };
}
  • main.js中,我们使用的Video类来自于video.js的导出,实际上已经是经过singleton函数改造的类,也就是上面这段代码中,return class {}这个匿名类。
  • 而对于v1v2,它们来自于ins这个实例对象,它由上面这段代码的new className()创建,也就是说它来自于最“简单”的、没有经过单例化的那个Video类。
  • 综上,v1并不是由那个匿名类创建的,所以它们不在同一原型链上。这也是这种单例模式实现方式的缺点,需要改进。

方法4:使用代理

这个方法是对方法3的改进,使用Proxy API对类进行代理,往新的类的原型上添加方法,也会被添加到原来的类的原型上,由此解决了方法3的缺点。

singleton.js

export function singleton(className){
    let ins;
    return new Proxy(className, {
        construct(target, ...args){
            if(!ins){
                ins = new target(...args);
            }
            return ins;
        }
    });
}

MDN对于Proxyconstruct更详细的介绍:handler.construct() - JavaScript | MDN (mozilla.org)

这里的constuct主要是拦截外部的new操作,函数参数target指向代理对象,也就是这里的className,即需要被单例化的类。

其它逻辑和方法3一致,使用闭包,通过ins存储实例对象。

video.js

import { singleton } from "./singleton.js";

class Video{
    constructor() {
        console.log("video created");
    }
}

const newVideo = singleton(Video);

export { newVideo as Video };

main.js

import { Video } from "./video.js";

const v1 = new Video();
const v2 = new Video();

console.log(v1 === v2);

Video.prototype.play = function(){
    console.log("play");
}

v1.play();

控制台输出

观察到构造函数只被调用了一次,并且在单例化的新类的原型上添加方法,实例对象v1也可以访问到。

这是因为newVideo是对Video的代理(这里的命名以video.js为准),在newVideo对象上的操作会被应用在Video这个对象上。

至此,完成了JS中较为完善的单例模式实现。文章来源地址https://www.toymoban.com/news/detail-760029.html

到了这里,关于[JS] JS单例模式的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式四:单例模式(Singleton)

    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。 通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。 单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象

    2024年02月15日
    浏览(46)
  • 单例模式(Singleton Pattern)

    单例模式(Singleton Pattern)是结构最简单的设计模式,它的 核心结构中只包含一个被称为单例类的特殊类 。通过 单例模式可以确保系统中一个类只有一个实例 ,且该实例易于被外界访问,从而方便对实例个数的控制并节约系统资源。 如何确保一个类只有一个实例并且这个实

    2024年02月03日
    浏览(64)
  • 单例模式(Singleton Pattern)

    单例模式(Singleton Pattern)是一种创建型设计模式,用于确保一个类只有一个实例,并提供全局访问点来获取该实例。 单例模式的特点是: 只允许类创建一个实例。 提供一个全局访问点来获取该实例。 对外部代码隐藏实例化过程,使得外部代码无法直接创建实例。 以下是一

    2024年02月15日
    浏览(35)
  • java设计模式-单例模式(Singleton)

    单例模式(Singleton)就是一个类只能有一个实例,自行实例化,并向系统提供这一实例,这个类就是单例类。单例模式的特点: 一个类只能有一个实例; 单例类自己实例化; 单例类给其它对象提供这个单一实例。 资源管理类经常被设计为单例模式,例如管理属性文件的类。

    2024年02月15日
    浏览(39)
  • C++ 中的单例模式singleton

    在面向对象编程中,设计模式是解决常见问题的最佳实践。单例模式是其中之一,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。在本文中,我们将详细介绍 C++ 中的单例模式。 单例模式是一种设计模式,它限制一个类只能创建一个对象。这个模式通常用

    2024年02月21日
    浏览(44)
  • 大话设计模式——9.单例模式(Singleton Pattern)

    简介 确保一个类只有一个实例,并提供全局访问点来获取该实例,是最简单的设计模式。 UML图: 单例模式共有两种创建方式: 饿汉式(线程安全) 提前创建实例,好处在于该实例全局唯一,不存在线程冲突;坏处在于未使用时也会占用内存资源。 懒汉式(原生写法存在线

    2024年04月12日
    浏览(49)
  • 《游戏编程模式》学习笔记(六)单例模式 Singleton Pattern

    保证一个类只有一个实例,并且提供了访问该实例的全局访问点。 定义这种东西一般都是不说人话的,要想要理解这句话的意思,我们得把它揉开了才能搞明白。 我们先看前半句 “保证一个类只有一个实例”,单例一般使用类来实现,也就是说,这个单例类,其有且只能有

    2024年02月12日
    浏览(44)
  • 《golang设计模式》第一部分·创建型模式-01-单例模式(Singleton)

    指目标类(Class)只有一个实例对象(Object),并且向使用该对象的客户端提供访问单例的全局方法。 保证类只有一个实例 有方法能让外部访问到该实例 懒汉式 在第一次调用单例对象时创建该对象,这样可以避免不必要的资源浪费 饿汉式 在程序启动时就创建单例对象,这

    2024年02月14日
    浏览(49)
  • 在序列化、反序列化下如何保持单例(Singleton)模式

    1、序列化、反序列化 在 Java 中,当一个对象被序列化后再被反序列化,通常情况下会创建一个新的对象实例。这是因为序列化将对象的状态保存到字节流中,而反序列化则是将字节流重新转化为对象。在这个过程中,通常会使用类的构造函数创建一个新的对象,并将保存的

    2024年02月13日
    浏览(29)
  • [JS] JS单例模式的实现

    单例模式(Singleton Pattern)是最简单的设计模式之一。这种类型的设计模式属于创建型模式,提供了一种创建对象的最佳方式。 特点 : 意图: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 主要解决: 一个全局使用的类频繁地创建与销毁。 何时使用: 当您想

    2024年02月04日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包