SessionStorage 踩坑记录:它真的能"只设置一次"吗?
背景
在前端开发中,我们经常使用sessionStorage来存储一些临时数据。最近在一个 Vue 项目中,我遇到了一个关于sessionStorage的有趣问题,这让我对它的特性有了更深入的理解。
问题描述
在项目的路由守卫中,我们有这样一段代码:
router.beforeEach(async (to, _from, next) => {
const userStore = useUserStore();
if (!SessionStorageService.getData("PROJECT_URL")) {
SessionStorageService.setData("PROJECT_URL", window.location.href);
}
// 其他代码...
next();
});最初,我没有加上if判断,直接使用:
router.beforeEach(async (to, _from, next) => {
const userStore = useUserStore();
SessionStorageService.setData("PROJECT_URL", window.location.href);
// 其他代码...
next();
});发现每次页面跳转,PROJECT_URL的值都会更新为当前页面的 URL,这与我的预期不符。我原以为sessionStorage是"设置一次后就不能更改"的,但实际上并非如此。
误区澄清
误区:sessionStorage 设置一次后就不能更改
这是一个常见误解。实际上,sessionStorage可以被多次覆盖,只要你调用setItem(或封装的setData方法),就会覆盖同一个 key 的原有值。
例如:
sessionStorage.setItem("foo", "123");
console.log(sessionStorage.getItem("foo")); // 输出: 123
sessionStorage.setItem("foo", "456");
console.log(sessionStorage.getItem("foo")); // 输出: 456sessionStorage 的特性
可多次更改:同一个 key 可以被多次设置,后面的值会覆盖前面的值
作用域限制:只在同一个标签页/窗口有效,关闭标签页后数据会清除
同源限制:只能被同源页面访问
容量较大:通常有 5MB 左右的存储空间
解决方案
如果你想实现"只设置一次"的效果,必须自己添加逻辑判断:
if (!SessionStorageService.getData("PROJECT_URL")) {
SessionStorageService.setData("PROJECT_URL", window.location.href);
}这样只有在sessionStorage中不存在该 key 时才会设置,实现了"只设置一次"的效果。
与其他存储方式对比
| 存储方式 | 是否可多次更改 | 生命周期 | 作用域 |
|---|---|---|---|
| sessionStorage | ✅ | 标签页会话 | 当前标签页 |
| localStorage | ✅ | 永久(除非手动清除) | 所有同源标签页 |
| cookie | ✅ | 可设置过期时间 | 可配置(domain/path) |
实现"只设置一次"的方法
如果你想封装一个"只设置一次"的方法,可以这样做:
function setOnce(key, value) {
if (sessionStorage.getItem(key) === null) {
sessionStorage.setItem(key, value);
return true; // 设置成功
}
return false; // 已存在,未设置
}经验教训
不要假设浏览器 API 的行为:在使用任何 API 前,最好先查阅文档,了解其真实行为
自己实现限制逻辑:如果需要特定的行为(如"只设置一次"),需要自己在代码层面实现
本地存储都是可覆盖的:sessionStorage、localStorage、cookie 等都可以被多次更改
结语
这次踩坑让我重新审视了前端存储的特性。记住,浏览器原生的存储机制都是可以多次更改的,没有"只写一次"的限制。如果你需要这样的功能,必须通过代码逻辑来实现。