浏览器存储

浏览器提供了在用户设备上保存数据的能力——主题偏好、登录状态、草稿内容等可以跨页面甚至跨会话保持。

localStorage — 持久存储

数据保存在浏览器中,除非手动清除,否则永远不会过期。关闭标签页、重启浏览器都不会丢失:

javascript
// 写入(值为字符串)
localStorage.setItem('username', '张三');
localStorage.setItem('theme', 'dark');

// 读取
const username = localStorage.getItem('username');
console.log(username); // "张三"

// 删除单个
localStorage.removeItem('theme');

// 清空全部
localStorage.clear();

// 获取键名(按索引)
console.log(localStorage.key(0)); // 第一个键名

// 总条数
console.log(localStorage.length);

存储对象和数组

localStorage 只能存字符串,存储复杂数据需要 JSON 转换:

javascript
const user = { name: '张三', age: 25, settings: { theme: 'dark' } };

// 存储
localStorage.setItem('user', JSON.stringify(user));

// 读取(注意:key 不存在时 getItem 返回 null)
const saved = JSON.parse(localStorage.getItem('user'));
console.log(saved?.name); // "张三",key 不存在时为 undefined

sessionStorage — 会话存储

用法与 localStorage 完全相同,区别在于数据在关闭标签页后自动清除

javascript
// 存储敏感或临时的会话数据
sessionStorage.setItem('authToken', 'abc123');

// 读取
const token = sessionStorage.getItem('authToken');

刷新页面数据还在,关闭标签页或浏览器则数据丢失。

特性localStoragesessionStorageCookie
容量~5-10MB~5-10MB~4KB
生命周期永久标签页关闭可设置过期时间
随请求发送到服务器是(自动)
作用域同源同源 + 同标签页同源 + 可设 path
API简单简单操作繁琐
适合场景用户偏好、缓存表单暂存、临时状态身份验证、跟踪

简单选择:需要服务器读取的数据(如登录 token)用 Cookie;不需要服务器参与的本地数据用 localStorage(持久)或 sessionStorage(会话)。

监听存储变化

storage 事件在其他标签页修改 localStorage 时触发(同一标签页不触发):

javascript
window.addEventListener('storage', (event) => {
  console.log(`键 "${event.key}" 被修改`);
  console.log(`旧值:${event.oldValue}`);
  console.log(`新值:${event.newValue}`);
  // 可用于跨标签页同步数据(如多标签页同时登出)
});

存储满时处理

javascript
try {
  localStorage.setItem('key', 'value');
} catch (error) {
  if (error.name === 'QuotaExceededError') {
    console.log('存储空间已满,请清理旧数据');
  }
}

实际应用示例

用户偏好保存

javascript
const themeToggle = document.querySelector('#theme-toggle');

// 读取已保存主题
const savedTheme = localStorage.getItem('theme') || 'light';
document.body.dataset.theme = savedTheme;

// 切换并保存
themeToggle.addEventListener('click', () => {
  const current = document.body.dataset.theme;
  const next = current === 'light' ? 'dark' : 'light';
  document.body.dataset.theme = next;
  localStorage.setItem('theme', next);
});

表单草稿自动保存

javascript
const form = document.querySelector('#post-form');

// 恢复草稿
const savedDraft = sessionStorage.getItem('draft');
if (savedDraft) {
  form.querySelector('textarea').value = savedDraft;
}

// 自动保存(每次输入时)
form.addEventListener('input', () => {
  const content = form.querySelector('textarea').value;
  sessionStorage.setItem('draft', content);
});

// 提交后清除
form.addEventListener('submit', () => {
  sessionStorage.removeItem('draft');
});