问题复现
最近在写 bug 的过程中发现一个有意思的事, 我把它称之为 ” sessionStorage
‘ 继承 ’ “。我们可以按以下做法复现这一过程:
测试一
打开一个页面(我们称之为 a 页面), 在控制台执行
sessionStorage.a = 'a';
window.open(window.location.href); // 得到 b 页面
我们把新打开的页面叫做 b 页面, 然后我们在 b 页面控制台执行
sessionStorage // 直接这么写是没有问题的,相当与获取 window 对象的 sessionStorage 属性
// 输出 {a: "a", length: 1}
按照我的认知, 一般认为 sessionStorage
是页面级的, 页面与页面之间互不影响。
对于上面这个例子, 我期待的输出应该只有一个 length
属性, 而不是这种类似 ’ 继承 ’ 的表现。
这和我的认知是有差异的, 我得查一下。在查文档之前, 我们先对这个问题进行简单的探索与分析。
初步分析
我按照我的认知测试了一下:
测试二
在 a 页面中执行
sessionStorage.a = 'a';
然后复制 a 页面的 url, 新建一个 tab 页打开这个 url, 执行
sessionStorage
// 输出 {length: 0}
嗯, 我的认知也对, 只是不全面, 缺乏特定场景下的补充。然后我对这个进行了进一步的探索。
在测试一的基础上我继续:
测试三
在 a 页面控制台执行
sessionStorage.a = 'aaaaaaaa';
sessionStorage.b = 'b';
在 b 页面执行
sessionStorage
// 输出 {a: "a", length: 1}
至此,综合测试一二三,我们大概可以得到这样的信息:
在 a 页面通过 window.open(window.location.href)
得到的 b 页面的 sessionStorage
会有
a 页面当前sessionStorage
的一份独立拷贝,此后再改变 a 页面的 sessionStorage
不会影响到 b 页面sessionStorage
;
这时候我又想,如果在 a 页面中打开的不是 window.location.href
这样一个地址,而是别的地址, 按照我们对 localStorage
和cookie
的了解,这里应该也有域的限制。所以我们接着测试:
测试四
我们在 a 页面 (非https://baidu.com
) 中打开一个别的域的地址得到 c 页面
window.open('https://baidu.com'); // 得到 c 页面
我们查看 c 页面的 sessionStorage
发现并没有 a 页面 sessionStorage
的那些值。恩,这点和我们认知是一样的,这个 ” 继承 ” 也只发生在同域的情况下。
所以,总结以上,我们可以得到这样的信息:
在 a 页面通过 window.open()
打开同域地址得到的 b 页面,b 页面会有 a 页面当前 sessionStorage
的一份独立拷贝,这两个 sessionStorage
互不影响。
大概就这么个结论,那我们去查看看文档,看看有没有文档提到这个结论。
文档支撑
经过一番搜索我通过这个问题 how-to-prevent-sessionstorage-being-inherited-when-using-target-blank-window 的答案找到的相应的文档描述。
When a new Document is created in a browsing context which has a top-level browsing context, the user agent must check to see if that top-level browsing context has a session storage area for that document’s origin. If it does, then that is the Document’s assigned session storage area. If it does not, a new storage area for that document’s origin must be created, and then that is the Document’s assigned session storage area. A Document’s assigned storage area does not change during the lifetime of a Document.
这是一份 html
标准文档(我理解这应该是给浏览器厂商看的实现规范),这里面有两个概念需要解释一下
-
browsing context
这个概念文档是这么解释的Abrowsing contextis the environment in which abrowserdisplays a
Document
(normally a tab nowadays, but possibly also a window or a frame within a page).Each browsing context has a specificorigin, host (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, host, and port all match.”), the origin of the active document, and a history that lists all the displayed documents in order.
简单理解,一个
tab
页、一个frame
就是一个browsing context
。 -
document's origin
这个文档也有解释Web content’s origin is defined by the scheme (protocol), host (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, host, and port all match.
简单理解,这就是我们常说的域。
明白了这两个概念,再看这段文档,这和我们测试得出来的结论是一样的, 更简单的总结就是:
在 a 页面中通过 window.open()
打开的同域页面中会有 a 页面当前 sessionStorage
的一份独立拷贝。
这就是这个看起来像 sessionStorage
继承问题的解释了。当然了这里的继承也并不是真正的继承,只是看起来像这么回事。
其他
在查文档的过程中我发现有些老兄想要避免这种 继承
,当然这种避免的方法也是有被人提到的(个人感觉不是很优雅),就是在新打开的 b 页面 load 完之后重置一下sessionStorage
,这样就避免受到上一个页面的影响了。
参考文档
- API/Using_the_Web_Storage_API
- API/Window/sessionStorage
- 项目中踩过的坑之 -sessionStorage
- how-to-prevent-sessionstorage-being-inherited-when-using-target-blank-window
- the-sessionstorage-attribute
- origin
- Browsing_context