js单例模式

单例模式是一种常见的设计模式,在JavaScript中也有广泛应用,以下是关于它的详细介绍:

定义

  • 单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在JavaScript中,虽然没有像传统面向对象语言中的类的概念,但可以通过对象字面量、构造函数、闭包等方式来实现单例模式。

实现方式

对象字面量方式

javascript 复制代码
const singleton = {
    property: "Some value",
    method: function() {
        console.log("This is a method in the singleton object.");
    }
};
  • 这种方式简单直接,创建了一个包含属性和方法的对象字面量,并且该对象在全局范围内只有一个实例。可以通过 singleton.propertysingleton.method() 来访问和调用其中的成员。

构造函数与闭包结合方式

javascript 复制代码
function Singleton() {
    if (!Singleton.instance) {
        Singleton.instance = this;
        this.property = "Some value";
        this.method = function() {
            console.log("This is a method in the singleton instance.");
        };
    }
    return Singleton.instance;
}

const instance1 = new Singleton();
const instance2 = new Singleton();

console.log(instance1 === instance2); // true
  • 在构造函数 Singleton 内部,通过判断 Singleton.instance 是否存在来确保只有一个实例被创建。如果不存在,则将当前实例赋值给 Singleton.instance ,并添加属性和方法。后续每次调用 new Singleton() 时,都会返回同一个实例。

使用ES6的类和静态属性

javascript 复制代码
class Singleton {
    constructor() {
        if (!Singleton.instance) {
            Singleton.instance = this;
            this.property = "Some value";
            this.method = function() {
                console.log("This is a method in the singleton instance.");
            };
        }
        return Singleton.instance;
    }

    static getInstance() {
        if (!Singleton.instance) {
            Singleton.instance = new Singleton();
        }
        return Singleton.instance;
    }
}

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // true
  • 定义了一个 Singleton 类,在构造函数中同样进行实例的唯一性判断和创建。同时,提供了一个静态方法 getInstance ,用于获取单例实例,这样可以更方便地在其他地方获取单例对象,而不需要直接调用构造函数。

应用场景

全局状态管理

  • 在JavaScript应用中,如Vuex、Redux等状态管理库的核心原理就部分地运用了单例模式。以Vuex为例,整个应用中的状态存储在一个唯一的store实例中,各个组件都可以访问和修改这个store中的状态,确保了状态的一致性和唯一性。
javascript 复制代码
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        increment(state) {
            state.count++;
        }
    }
});

export default store;

数据库连接池

  • 在与数据库交互的应用中,为了避免频繁地创建和销毁数据库连接,通常会使用数据库连接池来管理连接。连接池可以设计成单例模式,确保整个应用中只有一个连接池实例,所有需要数据库连接的地方都从这个连接池中获取连接,提高性能和资源利用率。
javascript 复制代码
const mysql = require('mysql');

class DatabasePool {
    constructor() {
        if (!DatabasePool.instance) {
            this.pool = mysql.createPool({
                connectionLimit: 10,
                host: 'localhost',
                user: 'root',
                password: 'password',
                database: 'mydb'
            });
            DatabasePool.instance = this;
        }
        return DatabasePool.instance;
    }

    getConnection(callback) {
        this.pool.getConnection(callback);
    }
}

const pool = new DatabasePool();
pool.getConnection((err, connection) => {
    if (err) throw err;
    // 使用连接进行数据库操作
    connection.release();
});

日志记录器

  • 在应用中,通常需要一个统一的日志记录器来记录各种操作和错误信息。单例模式可以确保整个应用中只有一个日志记录器实例,方便对日志进行统一管理和配置,避免多个日志记录器之间的冲突和混乱。
javascript 复制代码
class Logger {
    constructor() {
        if (!Logger.instance) {
            this.logs = [];
            Logger.instance = this;
        }
        return Logger.instance;
    }

    log(message) {
        const timestamp = new Date().toISOString();
        this.logs.push(`${timestamp} - ${message}`);
        console.log(message);
    }

    getLogs() {
        return this.logs;
    }
}

const logger = new Logger();
logger.log("This is a log message.");
logger.log("Another log message.");
console.log(logger.getLogs());

优点

  • 确保唯一性:保证一个类只有一个实例存在,避免了因创建多个实例而导致的资源浪费和数据不一致等问题。
  • 全局访问点:提供了一个全局可访问的点来获取该实例,方便在不同的模块和代码位置共享和使用该实例,提高了代码的可维护性和可扩展性。

缺点

  • 违反单一职责原则:单例类可能会承担过多的职责,因为它既要负责自身的实例化和管理,又要提供各种业务方法和属性,导致类的职责不单一,不利于代码的维护和测试。
  • 隐藏依赖关系:由于单例模式通常提供全局访问点,使得代码中对单例实例的依赖关系变得不明显,可能会导致代码的耦合度增加,不利于代码的解耦和重构。
相关推荐
1***s6322 小时前
Python爬虫反爬策略,User-Agent与代理IP
开发语言·爬虫·python
柒儿吖2 小时前
Qt for HarmonyOS 水平进度条组件开发实战
开发语言·qt·harmonyos
惜茶3 小时前
websocket操作入门
前端·javascript·websocket
咖啡の猫3 小时前
Python的自述
开发语言·python
摇滚侠3 小时前
Vue 项目实战《尚医通》,获取当前账户就诊人信息并展示出来,笔记42
前端·javascript·vue.js·笔记·html5
用户47949283569154 小时前
接手祖传代码后,我终于理解了"组合优于继承"
javascript
C.果栗子4 小时前
Blob格式的PDF文件调用打印,浏览器文件打印(兼容)
前端·javascript·pdf
夏霞4 小时前
c# ASP.NET Core SignalR 客户端与服务端自动重连配置指南
开发语言·c#·asp.net
@老蝴4 小时前
Java EE - 常见的死锁和解决方法
java·开发语言·java-ee
San30.6 小时前
从代码规范到 AI Agent:现代前端开发的智能化演进
javascript·人工智能·代码规范