原问题:
为什么 JS 中
localStroage
只能存string
类型的value
? 为什么这么设计?存值类型不行吗?
以下是回答备份:
存值类型不行吗?
理论上应当允许非 string
类型。像 localStorage
这种把持久存储的序列化/反序列化职责丢给用户层的设计,是不太符合使用习惯的,用这样的 API 写稍微复杂一点的逻辑就会很难用。而且后续 HTML 标准中的其他持久存储功能(如 IndexedDB,以及被废弃的 Web SQL),都是自带序列化和反序列化的。
为什么这么设计?
其实 localStorage
标准最早的草稿里是带序列化/反序列化的,但后来定稿中去掉了。
关于为什么作出这个改动,我发邮件问了当初的标准编辑 Ian Hickson 本人,但他说记不清楚了。
我在查了些资料后怀疑是为了简化标准降低实现难度,他对此表示认可,原话是:
Yeah that’s very plausible. Getting browser vendors on board is a big part of spec writing, so if they were expressing doubts I’d have been eager to simplify for them. There’s certainly an argument to be made that having the serialization be done in JS is simpler than having the browser do it, and pretty much just as powerful.
顺便在这里记录一下我查了哪些资料。
要找出这些有些年代的 HTML 标准的设计渊源,一般可以考虑从这几个地方入手:
- HTMLWG Bugzilla 上的 bug 报告
- #whatwg IRC 聊天存档
- [email protected] 以及 [email protected] 邮件列表存档
- WHATWG HTML 标准的 GitHub / SVN 提交历史,以及 http://web.archive.org/ 上的标准文档页面快照
不过这次 localStorage
标准实在是有点古老。
- 我先用 Google 的 search tools 确认了大概是 05-06 年间开始有相关讨论,标准应该就是在那段时间定下来的。
- 如此,排除了 Bugzilla (08 年才开设)。
- 接着,发现 标准相关的 IRC 聊天存档 只能追溯到 06 年 10 月份,而从 Web Archive 上找到的那个时期的标准草案已经是只能读写
string
类型的版本了,所以这条路也只好放弃。 - 邮件列表里用关键词 “storage” 或者 “persistent storage” 搜到的那个时期的发帖并不太多,大概浏览一遍可以确认没有关于序列化的讨论。
- 最后只能用二分法,一步步定位这段标准的具体修改历史了。
WHATWG 标准文档虽然是托管在 GitHub 上的(早期是 SVN,后来进行了迁移),但因为整个文档草稿都放在一个文件里,体积非常大,导致 blame 起来非常麻烦,难以查询定位。
好在 Web Archive 提供的 Wayback Machine 对于网页修改历史的记录很完整,带了可视化,并且可以看到渲染后的页面,因此选择从这里入手:http://web.archive.org/web/20060801000000*/http://whatwg.org/specs/web-apps/current-work/
最后发现 localStorage.getItem
这个方法的签名是在 2006/04/16 修改的,查 GitHub 提交记录,定位到这个提交。
虽然该提交没有进一步解释为什么这么改,但是仔细看具体修改的文字内容,其实是可以发现一些端倪的。
页面往下拉到高亮部分的修改,可以看到修改后的版本里删除了一大段关于 restored value 的描述。这部分主要是讲 localStorage
里存储字段的反序列化要求。
再仔细看修改前的文字,可以看到原始版本里有好几处省略号,分别是描述 E4X XML 对象、数组等的反序列化,说明之前这部分功能还没有确定应当如何实现,或者是碰到了困难。
再考虑到现在 IndexedDB 以及 history.state
所使用的 StructuredSerialize
/ StructuredDeserialize
算法(以前叫做 StructuredClone
) 是比 localStorage
晚了很久才出现在标准中的,我们可以猜想,当初 Web 领域对于 JS / DOM 中复杂对象的序列化/反序列化算法并没有一个共识,而如果要试图在这份草案中就达成这个共识的话,需要处理各种复杂的边界情况、要考虑到各种安全问题,还得让各个浏览器厂商统一意见,应该会极大影响标准讨论、撰写的进度。因此删掉这一部分很可能还是为了简化实现。
最后就是整理查找结果和猜想,发邮件给当事人,以获得印证了。