可封装 localstorage 为支持迭代和有序遍历的 map 类似对象:自动 json 序列化、实现 symbol.iterator/keys/values/entries/foreach,并通过 ls_keys 维护插入顺序,兼顾持久性与现代语义。

直接用 localStorage 存取键值对时,它只提供字符串键、字符串值的底层 API(setItem/getItem),本身不支持 for...of、entries() 或 forEach() 这类现代容器语义。但你可以通过轻量级的 Object 包装层,把它“伪装”成一个具备 Map 行为的可迭代对象——既保留 localStorage 的持久性,又获得结构化遍历能力。
封装一个 localStorage 包装类
核心是创建一个类或工厂函数,内部代理 localStorage 操作,并实现标准迭代协议(Symbol.iterator)和常用方法(keys、values、entries、forEach):
- 所有读写都自动做 JSON 序列化/反序列化,支持任意可序列化值(对象、数组、数字、布尔等)
- 实现
[Symbol.iterator]()方法,返回entries()迭代器,使for...of可直接使用 - 提供
keys()、values()、entries()三个方法,返回真正的迭代器(非数组),保持内存友好 -
forEach(callback)按插入顺序执行(localStorage 本身无序,但可通过维护一个键顺序数组来模拟)
保证键顺序与 Map 一致
localStorage 原生不记录插入顺序,所以需额外存储一个键列表(如 __ls_keys__)来维持逻辑顺序:
- 每次调用
set(key, value)时,先读取__ls_keys__,若 key 不在其中则 push 并保存 - 调用
delete(key)或clear()时同步更新该键列表 -
keys()、entries()等方法均基于该有序键列表生成迭代器,确保行为与 Map 一致
支持标准遍历语法
包装后,你可以像操作 Map 一样使用它:
-
for (const [key, value] of storage) { ... }—— 直接解构键值对 -
for (const key of storage.keys()) { ... }—— 遍历键 -
storage.forEach((value, key) => { ... })—— 类似 Map.forEach -
Array.from(storage.entries())或[...storage]—— 转为数组进行 filter/map 等操作
注意兼容性与边界处理
实际使用中需主动处理几个关键点:
- localStorage 容量限制(通常 5–10MB),写入前建议加 try/catch 并 fallback 提示
- 键名不能含控制字符或
\u0000,建议对 key 做简单校验或编码(如encodeURIComponent) - 值为
null或undefined时,JSON.stringify 会转为空字符串或忽略,应统一规范为null存储并显式还原 - 跨 tab 同步问题:其他标签页修改 localStorage 时,当前实例不会自动感知,如需响应,可监听
storage事件并触发自定义更新钩子










