一:前言
sessionStorage 和 localStorage 都是浏览器端的本地存储方案,核心区别在于 存储有效期、作用范围和数据持久化能力,
二:核心区别
对比维度 | sessionStorage | localStorage |
---|---|---|
存储有效期 | 临时存储:仅在 "当前会话" 有效(关闭当前标签页 / 浏览器后,数据自动删除) | 永久存储:除非手动删除(代码 / 浏览器清除),否则数据一直存在(即使关闭浏览器、重启电脑) |
作用范围 | 仅在 "当前标签页" 内共享(同一浏览器的不同标签页、不同窗口间不互通) | 在 "同一浏览器的同一域名" 下共享(同一域名的所有标签页、窗口都能访问,即使新打开标签页) |
数据容量 | 约 5MB(和 localStorage 一致,不同浏览器略有差异) | 约 5MB(和 sessionStorage 一致) |
数据持久化 | 非持久化:会话结束即销毁,不占用长期存储资源 | 持久化:数据长期保存在浏览器本地,可能占用存储容量 |
三:核心区别详细说明
1. 存储有效期:"临时会话" vs "永久留存"
- sessionStorage :数据绑定 "当前标签页的会话"------比如在 Chrome 打开一个标签页,存入
sessionStorage.setItem('name', '张三')
,只要不关闭这个标签页,刷新页面、跳转同域名页面,数据都在;但一旦关闭这个标签页(或关闭浏览器),数据直接消失,即使重新打开同一域名的新标签页,也获取不到之前的数据。 - localStorage :数据绑定 "域名" 而非 "会话"------存入
localStorage.setItem('theme', 'dark')
后,关闭浏览器、重启电脑,下次打开同一域名的页面,仍能通过localStorage.getItem('theme')
获取到 "dark",只有手动调用localStorage.removeItem('theme')
或在浏览器设置中清除 "网站数据",数据才会删除。
2. 作用范围:"单标签页隔离" vs "同域名共享"
- sessionStorage :同一浏览器的不同标签页完全隔离 ------比如在 Chrome 打开两个 "百度" 标签页(同一域名),在 A 标签页存入
sessionStorage.setItem('test', '123')
,在 B 标签页调用sessionStorage.getItem('test')
会返回null
,因为两个标签页的 sessionStorage 是独立的。 - localStorage :同一域名下所有标签页 / 窗口共享 ------同样在 A 标签页存入
localStorage.setItem('test', '123')
,在 B 标签页(同域名)能直接获取到'123'
,甚至新打开浏览器窗口访问同一域名,数据也能共享
3. 使用场景差异:"临时需求" vs "长期需求"
-
适合用 sessionStorage 的场景:
- 临时保存表单草稿(比如用户填写一半的表单,刷新页面不丢失,但关闭页面后无需留存);
- 临时传递数据(比如从页面 A 跳转至页面 B,传递临时参数,跳转后页面 B 使用完数据即可,无需长期保存);
- 临时登录状态(比如某些系统 "当前页有效" 的登录,关闭页面后重新登录)。
-
适合用 localStorage 的场景:
- 保存用户偏好(比如用户设置的 "深色模式",下次打开页面仍保持该设置);
- 记住非敏感信息(比如 "记住上次访问的页面""常用搜索关键词");
- 长期登录状态(比如部分网站 "7 天内免登录",通过 localStorage 存储登录令牌,有效期内无需重新登录)。
三、相同点与注意事项
1. 相同点
- 都仅在浏览器端存储,不与服务器交互(数据不会自动发送到后端,需手动通过 AJAX 传递);
- 都只能存储 字符串类型 (若要存储对象 / 数组,需用
JSON.stringify()
转为字符串,读取时用JSON.parse()
转回); - 都受 "同源策略" 限制(仅同一协议、同一域名、同一端口的页面能访问,不同域名无法跨域读取);
- 容量都约为 5MB(远大于 Cookie 的 4KB,适合存储较多数据)。
四:补充
"同源策略" 是浏览器为了安全设置的一道 "防护墙",简单说就是:只有 "协议、域名、端口号完全相同" 的网页,才能互相读取对方的 localStorage/sessionStorage 数据。
1、举例子:哪些情况能访问,哪些不能?
假设你在 http://www.example.com
这个页面存了 localStorage.setItem('name', '张三')
,看看其他页面能不能读到:
其他页面地址 | 是否同源? | 能不能读到 name 数据? |
原因分析 |
---|---|---|---|
http://www.example.com/page2 |
是 | 能 | 协议(http)、域名(www.example.com)、端口(80)都相同 |
https://www.example.com |
否 | 不能 | 协议不同(http vs https) |
http://sub.example.com |
否 | 不能 | 域名不同(www.example.com vs sub.example.com,子域名也算不同) |
http://www.example.com:3000 |
否 | 不能 | 端口不同(默认 80 vs 3000) |
http://www.another.com |
否 | 不能 | 域名完全不同 |
2、特殊情况:子域名能共享吗?(比如 a.example.com
和 b.example.com
)
默认情况下,子域名也属于 "不同源",不能互相访问 localStorage/sessionStorage。但可以通过 设置 document.domain
来实现 "主域名相同的子域名共享数据"(前提是两个子域名的主域名一致,比如都是 example.com
):
- 在
a.example.com
页面:
javascript
document.domain = 'example.com'; // 把当前页面的 domain 设为主域名
localStorage.setItem('user', '张三');
- 在
b.example.com
页面:
ini
document.domain = 'example.com'; // 同样设为主域名
const user = localStorage.getItem('user');
console.log(user); // 能读到 '张三',因为现在两者 domain 相同,视为同源
注意:这种方法只适用于 "主域名相同的子域名",且 document.domain
只能设置为 "当前域名的父域名"(不能随便设成其他无关域名)。
为什么会存在这样的特殊情况?
1、核心原因:满足 "同一业务体系下的子域名协同" 需求
很多大型网站或项目会用 不同子域名拆分功能 (比如一个公司下,pay.example.com
负责支付、user.example.com
负责用户中心、shop.example.com
负责商城),这些子域名虽然不同源,但属于 同一业务体系、同一信任域 (都是 example.com
主域名下的服务),天然需要共享一些非敏感数据(比如用户登录状态、通用配置)。
2、为什么不直接放开子域名访问,而要加 document.domain
限制?
如果浏览器默认允许所有子域名互相访问存储,会带来新的安全风险:
- 假设
example.com
主域名下,有一个自己开发的子域user.example.com
,还有一个第三方合作的子域partner.example.com
(比如广告合作)。如果默认允许子域互通,partner.example.com
就能偷偷读取user.example.com
里的用户信息,造成数据泄露。
document.domain
的规则要求 必须主动将所有子域的 document.domain
设为相同的主域名 (比如都设为 example.com
),才能共享数据 ------ 这相当于开发者主动 "声明":"这些子域是我信任的,允许它们互相访问",避免了 "默认开放" 带来的安全隐患**。**
五、混淆点说明
document.domain
解决的是 "不同子域名之间的数据共享" (比如 a.example.com
和 b.example.com
这两个不同域名的页面),而不管它们是否在同一个标签页;
sessionStorage 的 "标签页隔离" 指的是 "同一域名下的不同标签页之间的数据不共享" (比如 example.com
在标签页 A 和标签页 B 中的 sessionStorage 不互通)。
两者不冲突,分别针对不同的场景: 两者不冲突,分别针对不同的场景:
举两个例子说清楚:
例子 1:同一主域名的不同子域名(用 document.domain
解决)
假设:
- 页面 A 在
a.example.com
(子域名 A),存入sessionStorage.setItem('name', '张三')
; - 页面 B 在
b.example.com
(子域名 B),想读取name
。
默认情况下:
- 因为
a.example.com
和b.example.com
是不同子域名(不同源),即使在同一个标签页打开,页面 B 也读不到页面 A 的 sessionStorage(同源策略限制)。
通过 document.domain
后:
- 页面 A 和页面 B 都设置
document.domain = 'example.com'
(统一为主域名); - 此时两者视为 "同源",页面 B 可以读到页面 A 存在 sessionStorage 里的
name
(前提是它们在 同一个标签页 内,比如页面 A 跳转至页面 B)
页面 A 跳转至页面 B跳转方式
(核心:在当前标签页内切换 URL,不打开新标签页):
1.a链接,target="_self"
2.window.location.href...
例子 2:同一域名的不同标签页(sessionStorage 仍隔离)
假设:
- 标签页 A 打开
a.example.com
,存入sessionStorage.setItem('age', 20)
; - 标签页 B 也打开
a.example.com
(同一子域名),想读取age
。
此时:
- 即使两个标签页的域名完全相同(
a.example.com
),且都设置了document.domain = 'example.com'
; - 标签页 B 仍然读不到标签页 A 的
age
,因为 sessionStorage 是 "标签页级别的隔离"------ 同一域名的不同标签页,sessionStorage 各自独立,document.domain
无法改变这一点。
核心结论:
document.domain
只解决 "不同子域名之间的同源问题" (让主域名相同的子域名视为同源,从而能共享存储),但 不解决 "不同标签页之间的隔离问题" 。
- 对 sessionStorage:只有 "同一标签页 + 主域名相同(或通过
document.domain
统一) " 的页面,才能共享 sessionStorage;只要是 "不同标签页",哪怕域名完全相同,sessionStorage 也不互通。 - 对 localStorage:只要 "主域名相同(或通过
document.domain
统一) ",无论是否在同一标签页,都能共享 localStorage(因为 localStorage 是 "域名级别的共享",和标签页无关)。
六:扩展
1.document.domain
document.domain
是控制页面域名的属性,用于主域名相同的子域名之间共享数据;
一条完整url组成部分:
协议://子域名.主域名.顶级域名:端口号/路径/子路径?查询参数#哈希值 blog.example.com:8080/article/det...
2.sessionStoage或者localStorage支持设置有效期吗?
先说答案:不行!
不过可以通过在存储数据时主动设置有效期,达到类似的效果。
存储数据时:
javascript
// 1. 组装"数据+过期时间"的对象
const data = {
value: value, // 原始数据(支持任意类型,后续转字符串)
expireTime: Date.now() + expireSeconds * 1000 // 过期时间戳(毫秒)
};
获取数据时:
ini
const storedData = JSON.parse(storedStr);
const currentTime = Date.now();
if (currentTime > storedData.expireTime) {
// 过期:删除无效数据,返回 null
storage.removeItem(key);
return null;
}