学习前提

理解对象、数组、JSON字符串和DOM事件;存储示例在独立练习页面运行。

本课完成后你能做什么

为刷新后的状态设计可验证的存储格式,并在数据损坏时恢复。

先理解机制

JSON 表达字符串、数字、布尔值、null、数组和对象,不能完整保存函数、undefined、循环引用或原型。JSON.stringify 产生字符串,JSON.parse 还原普通数据;解析成功只说明语法有效,不代表字段类型符合应用要求。

localStorage 按源隔离并以字符串同步读写;相同源的其他页面能访问,用户也可以修改或清除。容量限制和隐私模式等可能使读写失败,应捕获错误并保留当前页面可用。它不适合敏感凭据,也不是跨设备数据库。

使用带项目名与版本的键减少冲突,读入后检查每个字段。迁移时先识别版本,再转换旧结构;未知版本不要盲目套用。只删除自己的键,不使用 localStorage.clear 清空整个站点其他功能的数据。

可运行示例

const KEY = "honeysuck-demo:progress:v1";
function loadProgress() {
  try {
    const data = JSON.parse(localStorage.getItem(KEY) ?? "null");
    return data && data.version === 1 && Array.isArray(data.done)
      ? data.done.filter(id => Number.isInteger(id) && id > 0) : [];
  } catch { return []; }
}
function saveProgress(done) {
  try {
    localStorage.setItem(KEY, JSON.stringify({ version: 1, done }));
    return true;
  } catch { return false; }
}
console.log(saveProgress([1, 3]), loadProgress());

推演与验证

在同源网页控制台运行,应读回1和3。把该键值改为破损JSON再调用loadProgress,结果应为空数组且页面不崩溃。用正确JSON但错误done类型再测试一次,确认结构验证生效。

常见错误与边界

catch返回空数组保证恢复,但实际产品还应提示保存失败,避免用户误以为已持久化。多个标签页写同一键时后写可能覆盖先写,storage事件只能通知变化,并不提供事务。

动手练习

加载时去掉重复id,并增加重置按钮,只移除本课程进度键。

参考解法与理由

验证后用Set去重,重置时removeItem(KEY),同时更新内存状态和界面。存储操作仍然放在try中。

进一步阅读