知乎回答备份

为什么 localStorage 只能存储 string 类型

Apr 4, 2020

原知乎回答链接

原问题:

为什么 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 标准的设计渊源,一般可以考虑从这几个地方入手:

不过这次 localStorage 标准实在是有点古老。

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 中复杂对象的序列化/反序列化算法并没有一个共识,而如果要试图在这份草案中就达成这个共识的话,需要处理各种复杂的边界情况、要考虑到各种安全问题,还得让各个浏览器厂商统一意见,应该会极大影响标准讨论、撰写的进度。因此删掉这一部分很可能还是为了简化实现。

最后就是整理查找结果和猜想,发邮件给当事人,以获得印证了。

Some rights reserved
Except where otherwise noted, content on this page is licensed under a Creative Commons Attribution-ShareAlike 4.0 International license.