问题复现
最近在写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
这个概念文档是这么解释的A browsing contextis the environment in which a browserdisplays 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