localStorage只能存储字符串,存对象需用JSON.stringify序列化,取用JSON.parse解析;无自动过期,但可能被清空或超配额;同步阻塞主线程;跨标签页需监听storage事件。

localStorage 不能存对象,直接 setItem 对象会变成 [object Object] —— 这是绝大多数人第一次踩的坑。
localStorage 只接受字符串,对象必须手动序列化
它底层只支持字符串键值对,任何非字符串类型(包括数字、布尔、null、undefined、对象、数组)都会被隐式转成字符串。比如 localStorage.setItem('count', 42) 实际存的是 "42";而 localStorage.setItem('user', {name: 'Alice'}) 存的是 "[object Object]",取出来就废了。
正确做法是显式用 JSON.stringify 和 JSON.parse:
const user = { name: 'Alice', age: 30 };
localStorage.setItem('user', JSON.stringify(user));
// 取出时
const savedUser = JSON.parse(localStorage.getItem('user'));
注意:JSON.stringify 无法处理函数、undefined、Date、RegExp、循环引用等,遇到这些要提前清洗或换方案(如 structuredClone + indexedDB)。
立即学习“Java免费学习笔记(深入)”;
localStorage 没有过期机制,但可能被手动清空或超出配额
它不会自动过期,也不会因页面关闭而消失,但以下情况数据会丢失:
- 用户手动清除浏览器缓存或“网站数据”
- 调用了
localStorage.clear()或localStorage.removeItem('key') - 存储超过浏览器限制(通常 5–10MB),此时
setItem会抛出QuotaExceededError
建议操作前加 try-catch:
try {
localStorage.setItem('config', JSON.stringify(config));
} catch (e) {
if (e.name === 'QuotaExceededError') {
console.warn('localStorage 已满');
}
}
localStorage 是同步阻塞的,大量数据会影响主线程
读写都发生在主线程,且是同步操作。如果存的是几 MB 的大字符串(比如未压缩的日志数组),getItem 可能卡住 UI 几百毫秒。
优化建议:
- 只存必要字段,避免 dump 整个状态树
- 高频更新场景改用内存缓存(
Map或变量),定时或节流后持久化 - 超大结构考虑
indexedDB,它支持异步、二进制、索引查询
跨标签页监听数据变化要用 storage 事件
同一个域名下,一个标签页调用 setItem,其他同源标签页不会自动感知。必须主动监听 storage 事件:
window.addEventListener('storage', (e) => {
if (e.key === 'theme') {
document.documentElement.setAttribute('data-theme', e.newValue);
}
});
注意:storage 事件在触发它的那个页面**不会**触发,只通知其他同源页面;e.oldValue 和 e.newValue 都是字符串,且 e.url 是修改来源页面的完整 URL。
真正难搞的是:没有内置的“更新就刷新”机制,所有依赖 localStorage 的状态都要自己补监听逻辑——这点常被忽略,直到多窗口操作时数据不一致才暴露。











