函数表达式本身不直接构成单例,真正起作用的是它配合立即执行(iife)所形成的闭包结构;核心是用私有作用域锁住instance变量,仅暴露getinstance等可控入口,实现惰性初始化、状态封装与唯一实例复用。

函数表达式本身不直接构成单例,真正起作用的是它配合立即执行(IIFE)所形成的闭包结构。核心逻辑是:用私有作用域锁住实例变量,只暴露一个可控的访问入口。
闭包封装实例状态
把 instance 变量声明在 IIFE 内部,它就成为闭包的私有变量。外部代码既不能直接读取,也无法重新赋值或删除。只有 IIFE 返回的函数(比如 getInstance 或构造器)能持续访问它。
- instance 生命周期由闭包维持,不会因函数执行结束而销毁
- 所有后续调用都复用这个被“封存”的 instance
- 即使多次调用返回的函数,也始终操作同一个内存地址的对象
惰性初始化与首次校验
实例不是在定义时创建,而是在第一次调用时才生成。返回的函数内部会检查 instance 是否已存在,未创建则 new 实例并缓存,否则直接返回已有引用。
- 节省资源,避免模块加载时就初始化无用对象
- 支持传参定制(如配置项),但仅首次生效,后续调用忽略参数
- 构造逻辑、私有字段(如 _connectedAt、_retryCount)可安全藏在闭包内
单一可控出口设计
不导出 instance 本身,也不暴露构造函数供外部 new。只返回一个函数作为唯一入口,所有获取实例的行为都必须经过它。
- 防止使用者绕过控制逻辑,例如直接 new Connection() 或修改 instance
- 避免返回对象中包含对 instance 的引用,导致外部间接篡改
- 适合封装需统一管理的资源,如数据库连接、日志器、WebSocket 客户端
为什么不用箭头函数
箭头函数不能直接用于 IIFE,语法上不允许 (() => {})() 这样的写法。它没有自己的 this 和 arguments,更重要的是无法承载独立作用域——而封闭性正依赖这个作用域来隔离变量。
- 正确写法只能是 (function() { ... })() 或 (function() { ... }())
- 若强行用箭头函数,必须嵌套在普通函数内,否则 instance 会暴露在模块顶层
- 传统函数表达式是实现作用域隔离和闭包封装的必要基础










