详细讲解在JavaScript中读写LocalStorage与SessionStorage的标准方法,涵盖核心API调用、复杂数据对象的JSON序列化处理、配额溢出与异常防护,以及两者生命周期差异与跨标签页通信机制。
JavaScript怎么读写LocalStorage与SessionStorage
时间:2026-11-05
浏览:462
文章目录
window 下,共用一套简洁的标准读写方法(setItem、getItem、removeItem、clear)。两者的本质区别不在于调用接口,而在于数据的生命周期与隔离作用域。掌握两者的规范读写流程、对象序列化手段以及边界异常处理,能够有效保证客户端数据管理的稳定可靠。
一、核心 API 接口与基础读写操作
localStorage 与 sessionStorage 是 Storage 接口的两个不同实例。无论操作哪一个对象,读写接口完全统一。在进行读写时,建议始终调用标准 API,而不是直接通过对象属性访问(例如 localStorage.key = value),因为标准方法能规范化处理保留关键字并确保各浏览器行为一致。
1. 写入数据:setItem(key, value)
使用 setItem() 方法向存储区域添加一个键值对。如果该键已经存在,旧的值会被新值覆盖;如果不存在,则创建新的键值对。
// 向 localStorage 写入用户名与用户偏好
window.localStorage.setItem('username', 'alex_coder');
window.localStorage.setItem('app_theme', 'dark');
// 向 sessionStorage 写入当前页面的临时标签状态
window.sessionStorage.setItem('current_step', 'step_2');
2. 读取数据:getItem(key)
使用 getItem() 方法通过键名获取对应的值。如果指定的键存在,返回对应的字符串值;如果键不存在,则统一返回 null。
// 读取已存储的键
const theme = window.localStorage.getItem('app_theme');
console.log(theme); // 示例输出: "dark"
// 读取未声明的键
const missingItem = window.localStorage.getItem('unknown_key');
console.log(missingItem); // 示例输出: null
3. 删除与清空操作:removeItem(key) 与 clear()
当某些缓存数据失效或用户主动退出登录时,需要及时移除存储数据:
removeItem(key):删除指定的单项键值对。若键名不存在,该方法静默处理,不抛出异常。clear():彻底清空当前域名(同源)在当前存储区域下的所有键值对。
// 删除单项数据
window.localStorage.removeItem('username');
// 确认删除结果
console.log(window.localStorage.getItem('username')); // 示例输出: null
// 清空 sessionStorage 全部数据
window.sessionStorage.clear();
4. 遍历与获取总量:length 与 key(index)
Storage 对象还具备 length 只读属性与 key(index) 方法,方便对当前存储的所有项进行完整检查与遍历:
const storage = window.localStorage;
console.log('存储项总量:', storage.length);
for (let i = 0; i < storage.length; i++) {
const k = storage.key(i);
const v = storage.getItem(k);
console.log(`[#${i}] ${k} = ${v}`);
}
二、处理对象、数组与复杂数据的序列化
Web Storage 的底层实现只接受 UTF-16 DOMString(字符串类型)。如果向 setItem() 传入非字符串值(如对象、数组、数字、布尔值),浏览器会自动调用其内置的 toString() 方法实施隐式类型转换。
如果直接执行
localStorage.setItem('user', { id: 1, name: 'Alice' }),存储引擎实际写入的是字符串 "[object Object]"。这不仅丢失了全部属性信息,后续读取也再无法还原。
为了能够准确存储和读取复杂的 JavaScript 实体,必须在写入前使用 JSON.stringify() 进行序列化,并在读取后使用 JSON.parse() 进行反序列化。同时,反序列化过程应当配合 try...catch 进行保护,避免因存储了损坏数据导致整个页面脚本崩溃。
// 1. 定义待存储的复合业务对象
const userProfile = {
id: 10086,
name: '张三',
roles: ['admin', 'editor'],
lastLogin: new Date().toISOString()
};
// 2. 序列化写入
try {
const serializedData = JSON.stringify(userProfile);
window.localStorage.setItem('user_profile', serializedData);
} catch (err) {
console.error('序列化写入失败:', err);
}
// 3. 安全读取与反序列化还原
function getUserProfile() {
const rawString = window.localStorage.getItem('user_profile');
if (!rawString) {
return null; // 键不存在
}
try {
return JSON.parse(rawString);
} catch (parseError) {
console.warn('解析本地存储数据异常,重置为默认值:', parseError);
return null;
}
}
const currentUser = getUserProfile();
console.log(currentUser?.name); // 示例输出: "张三"
三、LocalStorage 与 SessionStorage 的特性差异与应用选型
虽然两者在 API 语法上没有差异,但在实际工程架构中,它们的存储位置与生效机制存在明显区别。
1. 数据生命周期(Lifecycle)
- LocalStorage:属于持久化存储。数据存放在操作系统的本地磁盘数据库中,只要代码没有执行
removeItem或clear,且用户未手动清理浏览器缓存,数据就会一直保留,即便关闭浏览器或重启电脑依然存在。 - SessionStorage:属于临时会话存储。数据保留在当前顶级浏览上下文的内存中。当用户关闭该标签页或关闭浏览器窗口时,对应的存储内容会立即被销毁释放。需要注意,页面刷新(F5 / Reload)不会丢失 SessionStorage。
2. 作用域与标签页隔离(Scope & Isolation)
- LocalStorage:受同源策略(协议 + 域名 + 端口)约束。同一个源下打开的所有标签页和窗口,全部共享同一份 LocalStorage 数据仓库,任意标签页的修改对其他标签页立即可见。
- SessionStorage:不仅受同源策略约束,而且严格限制在当前标签页上下文中。在同一个浏览器中打开两个相同网址的独立标签页,它们各自拥有独立的 SessionStorage,互不干扰、互不连通。
| 技术指标 | LocalStorage | SessionStorage |
|---|---|---|
| 存储生命周期 | 持久保留,直到代码清除或用户清空浏览器数据 | 仅在当前页面会话有效,关闭标签页即销毁 |
| 跨标签页共享 | 同源下的所有标签页与窗口无缝共享 | 仅当前标签页独占,同源不同标签页彼此隔离 |
| 典型存储容量 | 约 5MB(同源共享此配额) | 约 5MB(每个独立会话独享该配额) |
| 跨页面事件通信 | 写入会自动向同源其他活跃标签页广播 storage 事件 |
仅在同页面嵌入的同源 iframe 间触发,不跨标签页 |
| 最佳适用场景 | 用户界面主题设置、系统语言偏好、离线配置、全局状态标记 | 多步骤注册/下单表单数据草稿、单次会话筛选条件、页内撤销栈 |
四、异常捕获、存储限制与跨标签页通信
1. 存储容量与 QuotaExceededError 异常处理
主流浏览器分配给 Web Storage 的配额一般限制在 5MB 左右(以 UTF-16 字符编码计算,约 250 万到 500 万字符)。当存储内容超过上限,或者用户开启了严苛的私密浏览模式导致写入被拦截时,调用 setItem() 将直接抛出 QuotaExceededError(DOMException 代码 22)。因此,在生产环境中,封装一个健壮的存储访问器必不可少。
/**
* 健壮的 LocalStorage 安全读写包装器
*/
class SafeLocalStorage {
// 写入数据(支持对象自动序列化与异常保护)
static set(key, value) {
try {
const payload = JSON.stringify(value);
window.localStorage.setItem(key, payload);
return true;
} catch (error) {
// 专门识别配额溢出
if (error.name === 'QuotaExceededError' || error.code === 22) {
console.error('LocalStorage 存储空间超限,写入已放弃:', key);
} else {
console.error('写入本地存储失败:', error);
}
return false;
}
}
// 读取数据(支持自动反序列化与默认值降级)
static get(key, defaultValue = null) {
try {
const raw = window.localStorage.getItem(key);
if (raw === null) return defaultValue;
return JSON.parse(raw);
} catch (error) {
console.warn(`读取键 [${key}] 失败,返回降级默认值:`, error);
return defaultValue;
}
}
}
// 调用示例
SafeLocalStorage.set('user_config', { notify: true, volume: 80 });
const config = SafeLocalStorage.get('user_config', { notify: false });
2. 监听 storage 事件实现跨标签页通信
当任意一个标签页对 localStorage 执行了 setItem()、removeItem() 或 clear() 操作时,浏览器会自动在同源的其他所有打开的标签页中触发 storage 事件。
发起修改操作的当前标签页自身不会触发
storage 事件,只有同源的其他标签页能捕获到该事件。这使得它非常适合用来实现跨标签页的多端状态同步(例如单点登出、实时切换主题等)。
// 在其他标签页中注册监听器
window.addEventListener('storage', (event) => {
console.log('检测到同源存储发生变更:');
console.log('被修改的键名:', event.key);
console.log('原数值:', event.oldValue);
console.log('新数值:', event.newValue);
console.log('触发页面的URL:', event.url);
// 场景示例:全局主题同步
if (event.key === 'app_theme' && event.newValue) {
document.body.className = event.newValue;
}
// 场景示例:用户在另一窗口登出,本窗口同步刷新或跳转
if (event.key === 'auth_token' && event.newValue === null) {
alert('您已在其他窗口退出登录,本页面即将刷新');
window.location.reload();
}
});
五、常见避坑与安全规范
1. 警惕布尔值与空值的真值判断误区
当执行 localStorage.setItem('isVip', false) 时,底层存储的其实是字符串 "false"。在 JavaScript 中,非空字符串 "false" 在隐式布尔转换中判定为真:
localStorage.setItem('isVip', false);
// ❌ 错误判断:字符串 "false" 会被判定为 true!
if (localStorage.getItem('isVip')) {
console.log('错误:依然被判定为 VIP 用户');
}
// ✔ 正确判断:明确与字符串比较,或者使用 JSON.parse 反序列化
const isVip = localStorage.getItem('isVip') === 'true';
console.log(isVip); // 输出: false
2. 严禁存储敏感身份凭据(防范 XSS 攻击)
Web Storage 中存储的内容对于当前页面同源下的所有 JavaScript 脚本完全可见,且没有任何类似 Cookie 的 HttpOnly 保护标志。一旦网站存在跨站脚本(XSS)漏洞,攻击者可直接通过 localStorage.getItem() 将保存在其中的敏感数据(如用户敏感私钥、身份证号、支付密码、长期凭证等)发送至远程恶意服务器。对于高安全要求的登录会话 Token,应优先使用设置了 HttpOnly 与 Secure 属性的 Cookie 维护。
3. 注意同步阻塞对页面渲染性能的影响
Web Storage 的所有读写操作均在主线程同步执行。这意味着在执行 setItem() 或 getItem() 时,主线程会被阻塞,直到数据写入或读取完毕。如果存储了接近 5MB 的大体积 JSON 字符串,频繁的序列化与磁盘写入会导致动画掉帧和界面卡顿。如果项目需要存储大量结构化数据、二进制文件或大列表,应当选用异步的 IndexedDB。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。