javascript设计模式有哪些_如何用单例模式创建唯一对象?
发布时间 - 2026-01-09 00:00:00 点击率:次单例模式的本质是逻辑约束而非语法限制,确保类在整个应用生命周期中仅初始化一次且返回同一实例;适用于配置管理、日志器等跨模块共享组件,不适用于需多实例的场景。
单例模式的核心判断:是否真需要全局唯一实例?
JavaScript 里 new 一个对象、用字面量 {} 或 Object.create(null) 都能快速创建对象,但“单例”不是语法限制,而是逻辑约束:确保整个应用生命周期中,某个类最多被初始化一次,且所有调用都返回同一个实例。别为了设计模式而单例——比如配置管理、日志器、状态仓库这类跨模块共享且无状态/轻状态的组件才适合;频繁创建不同参数的实例(如用户卡片、API 请求封装)硬套单例反而导致耦合和难以测试。
最简可行的单例实现:闭包 + 静态属性
ES6+ 环境下,用类配合静态属性是最直观的方式。关键点在于:实例缓存在类自身上,构造函数不直接暴露,而是通过静态方法控制创建时机。
class Logger {
constructor() {
if (Logger.instance) {
return Logger.instance;
}
this.logs = [];
Logger.instance = this;
}
static getInstance() {
return Logger.instance || new Logger();
}
log(msg) {
this.logs.push(`${new Date().toISOString()}: ${msg}`);
}
}
// 使用
const a = Logger.getInstance();
const b = Logger.getInstance();
console.log(a === b); // true
注意:Logger.instance 是手动维护的引用,如果误删或重赋值(如 Logger.instance = null),下次调用 getInstance() 会新建实例,破坏单例性。生产环境建议加 Object.freeze(Logger) 锁定构造函数本身。
更健壮的写法:利用 Symbol 防止外部篡改
用 Symbol 作私有键名,避免 instance 被意外覆盖。同时把初始化逻辑收进静态 getter,让调用更自然。
class Database {
constructor() {
if (Database[Database.instanceSymbol]) {
return Database[Database.instanceSymbol];
}
this.connection = 'fake-connection-string';
Database[Database.instanceSymbol] = this;
}
static get instanceSymbol() {
if (!Database._instanceSymbol) {
Database._instanceSymbol = Symbol('db-instance');
}
return Database._instanceSymbol;
}
static get instance() {
return Database[Database.instanceSymbol] || new Database();
}
}
// 使用
const db1 = Database.instance;
const db2 = Database.instance;
console.log(db1 === db2); // true
这个版本的关键差异:
-
Symbol键无法被for...in或Object.keys()枚举,外部代码几乎无法干扰 - 静态
get instance()
语法比 getInstance()更符合直觉,也避免忘记加括号 - 仍需注意:若模块被多次
import(如在不同打包上下文),每个导入副本会拥有独立的Symbol和静态属性,此时单例失效——这是模块系统层面的问题,不是单例逻辑缺陷
常见陷阱:懒加载 vs 构造时副作用
上面例子都是“懒加载”:第一次调用时才初始化。但如果你的单例构造函数里有副作用(如发起网络请求、绑定全局事件、修改 DOM),要格外小心:
- 如果多个模块几乎同时调用
getInstance(),可能触发多次构造(因检查和赋值非原子操作) - 异步初始化(如
await initDB())会让单例变成“伪单例”:返回的是 Promise,而非实例本身 - 服务端渲染(SSR)中,单例在 Node.js 进程内共享,多个请求共用同一实例,容易引发状态污染
真正安全的异步单例需要双重检查 + Promise 缓存,且必须明确文档化其线程/请求隔离边界。多数场景下,宁可把初始化拆到启动阶段(如 initApp()),也不在 getInstance 里埋异步逻辑。
单例最难的不是写法,是厘清“唯一”的作用域——是当前 JS 执行上下文?当前模块导入链?还是整个浏览器 Tab?没想清楚这点,代码越“规范”,问题越隐蔽。
# javascript
# es6
# java
# js
# node.js
# node
# 浏览器
# app
# 懒加载
# ai
# 作用域
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何用wdcp快速搭建高效网站?
如何实现建站之星域名转发设置?
Python函数文档自动校验_规范解析【教程】
软银砸40亿美元收购DigitalBridge 强化AI资料中心布局
如何确保西部建站助手FTP传输的安全性?
laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析
js代码实现下拉菜单【推荐】
Claude怎样写约束型提示词_Claude约束提示词写法【教程】
北京专业网站制作设计师招聘,北京白云观官方网站?
Android中AutoCompleteTextView自动提示
mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?
Laravel怎么实现验证码(Captcha)功能
VIVO手机上del键无效OnKeyListener不响应的原因及解决方法
Google浏览器为什么这么卡 Google浏览器提速优化设置步骤【方法】
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
轻松掌握MySQL函数中的last_insert_id()
Win11搜索不到蓝牙耳机怎么办 Win11蓝牙驱动更新修复【详解】
jQuery validate插件功能与用法详解
长沙做网站要多少钱,长沙国安网络怎么样?
Laravel Telescope怎么调试_使用Laravel Telescope进行应用监控与调试
,在苏州找工作,上哪个网站比较好?
php静态变量怎么调试_php静态变量作用域调试技巧【解答】
国美网站制作流程,国美电器蒸汽鍋怎么用官方网站?
广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
Java类加载基本过程详细介绍
如何在万网主机上快速搭建网站?
Laravel怎么解决跨域问题_Laravel配置CORS跨域访问
Laravel如何构建RESTful API_Laravel标准化API接口开发指南
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】
HTML5空格在Angular项目里怎么处理_Angular中空格的渲染问题【详解】
php 三元运算符实例详细介绍
教学论文网站制作软件有哪些,写论文用什么软件
?
Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性
如何快速查询域名建站关键信息?
大学网站设计制作软件有哪些,如何将网站制作成自己app?
Laravel如何使用Service Container和依赖注入?(代码示例)
微信推文制作网站有哪些,怎么做微信推文,急?
Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势
ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】
Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程
Laravel如何使用Passport实现OAuth2?(完整配置步骤)
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
简历没回改:利用AI润色让你的文字更专业
Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)
C#如何调用原生C++ COM对象详解
非常酷的网站设计制作软件,酷培ai教育官方网站?
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
无锡营销型网站制作公司,无锡网选车牌流程?


语法比