单例模式封装浏览器本地存储代理器确保全局唯一实例,统一处理读写、序列化、错误兜底与扩展(如过期、驱动切换);避免状态不一致、内存浪费,便于集中控制策略及后续无缝替换底层实现。

用单例模式封装浏览器本地存储代理器,核心是确保整个应用中只存在一个存储管理实例,统一处理读写、序列化、错误兜底和未来扩展(比如加过期时间、切换驱动)。它不是简单把 localStorage 包一层,而是构建一个可控、可维护、有边界的行为中枢。
为什么必须用单例?
避免多个地方各自操作 localStorage 导致状态不一致;防止重复初始化、内存浪费;便于集中控制策略(如统一加前缀、统一异常捕获、统一日志埋点);后续若要替换为 IndexedDB 或加加密层,只需改单例内部,调用方完全无感。
基础单例结构(闭包 + IIFE)
这是轻量、无依赖、兼容性好的实现方式:
const StorageProxy = (function () {
let instance = null;
function init() {
// 检查环境支持
if (!window.localStorage) {
throw new Error('localStorage not supported');
}
return {
set(key, value) {
try {
const serialized = JSON.stringify(value);
localStorage.setItem(key, serialized);
} catch (e) {
console.warn(`Storage set failed for ${key}:`, e.message);
}
},
get(key) {
try {
const raw = localStorage.getItem(key);
return raw ? JSON.parse(raw) : null;
} catch (e) {
console.warn(`Storage get failed for ${key}:`, e.message);
return null;
}
},
remove(key) {
localStorage.removeItem(key);
},
clear() {
localStorage.clear();
}
};
}
return {
getInstance() {
if (!instance) {
instance = init();
}
return instance;
}
};
})();
// 使用
const storage = StorageProxy.getInstance();
storage.set('user', { id: 1, name: 'Alice' });
console.log(storage.get('user')); // { id: 1, name: 'Alice' }
增强版:支持驱动切换与过期逻辑
真正工程可用的代理器需预留扩展性。用“适配器模式”配合单例,可轻松切换 localStorage / sessionStorage,甚至未来接入内存缓存或后端 fallback:
- 定义统一接口:
get、set、remove、clear、has - 每个驱动(如 LocalDriver、SessionDriver)实现该接口
- 单例内部持有一个驱动实例,默认用
localStorage,可通过useDriver()切换 - 在
set中自动注入时间戳和 TTL(如{ value: ..., expires: Date.now() + 3600000 }),get时校验过期并自动清理
关键细节不能忽略
实际封装时这几个点决定稳定性:
-
JSON 安全性:对
undefined、函数、Symbol 等无法序列化的值做预处理(如转为null或跳过) - 容量保护:写入前估算字符串长度,超限(如 >4.8MB)主动 warn 并拒绝写入,避免静默失败
-
跨域隔离:不同子域名间
localStorage不共享,代理器可自动添加 domain 前缀(如myapp:user)避免 key 冲突 - 错误静默 vs 报错:生产环境建议 warn 而非 throw,避免因存储异常导致主流程崩溃


















