localStorage只支持字符串值,非字符串类型会自动调用toString()导致数据损坏;应统一用JSON.stringify()存、JSON.parse()取,并加try/catch;偏好键名需加前缀隔离,监听storage事件仅适用于跨tab同步,单页内需手动触发更新。

localStorage.setItem 为什么存进去的总是字符串?
因为 localStorage 只支持字符串值,任何非字符串类型(比如对象、数组、布尔值、数字)都会被自动调用 toString() 转换——{theme: 'dark'} 存进去变成 [object Object],取出来就废了。
正确做法是手动序列化和反序列化:
- 存之前用
JSON.stringify()转成字符串 - 取之后用
JSON.parse()还原(注意加try/catch,防止存储损坏或手动改过值) - 布尔值和数字也建议统一走 JSON 流程,避免
true.toString() === 'true'这种看似能用但类型丢失的问题
如何安全地读写用户偏好键名(比如 theme、fontSize、autoSync)
别直接拼接字符串当 key,容易拼错或污染全局命名空间。建议封装一个带前缀的访问器:
const PREFERENCE_PREFIX = 'user_pref_';
function setPreference(key, value) {
localStorage.setItem(PREFERENCE_PREFIX + key, JSON.stringify(value));
}
function getPreference(key, defaultValue = null) {
const raw = localStorage.getItem(PREFERENCE_PREFIX + key);
try {
return raw ? JSON.parse(raw) : defaultValue;
} catch {
return defaultValue;
}
}这样 setPreference('theme', 'dark') 实际存的是 user_pref_theme,和其他业务数据隔离,也方便批量清理(比如清空所有以 user_pref_ 开头的项)。
监听 localStorage 变化:页面间同步偏好为什么失效?
localStorage 本身不触发当前页面的 storage 事件——只有在其他同源 tab 或 window 中修改时,当前页才会收到通知。所以单页内改完不触发更新,必须手动处理。
- 写入后立即触发自定义事件(如
dispatchEvent(new Event('preferencechange'))),让组件响应 - 监听
storage事件只用于跨 tab 同步:window.addEventListener('storage', e => { if (e.key?.startsWith('user_pref_')) { /* 更新本地状态 */ } }) - 注意:Safari 在无痕模式下可能直接禁用
localStorage,需兜底(比如 fallback 到内存对象)
localStorage 清理和容量陷阱
5MB 是常见上限(实际因浏览器而异),但真正麻烦的是「存了删不干净」——比如用户切换账号后没清除旧偏好,或者 key 名随版本迭代变混乱。
- 避免用时间戳、UUID 等动态 key;偏好项应有稳定语义名(
theme而不是theme_v2_1712345678) - 提供显式重置函数:
function resetPreferences() { Object.keys(localStorage).filter(k => k.startsWith('user_pref_')).forEach(k => localStorage.removeItem(k)); } - 上线前用
localStorage.length和Object.keys(localStorage)快速检查是否有残留测试 key
最常被忽略的一点:localStorage 没有过期机制,也不区分用户登录态。只要没手动清,上次存的 dark mode 会一直跟着这个域名,哪怕用户已登出或换了设备。

















