localStorage
和 sessionStorage
都是现代浏览器提供的客户端数据存储机制,它们属于 HTML5 Web Storage API 的一部分。它们都允许网页在用户浏览器中存储键值对数据,但其 生命周期 和 作用域 是核心区别。
一、核心概念与共同点
在深入探讨区别之前,先了解它们的共同点:
- 客户端存储:数据存储在用户浏览器中,不会自动发送到服务器。
- 键值对(Key-Value Pair):数据以键(字符串)和值(字符串)的形式存储。
- 同源策略(Same-Origin Policy):只有来自相同协议、域名和端口的网页才能访问同一份存储数据。这是重要的安全机制。
- 简单易用:提供了简单直观的 API 接口。
- 存储容量:通常比
Cookies
大得多,通常为 5MB 到 10MB(取决于浏览器)。
二、关键区别一览表
特性 / 类别 | localStorage | sessionStorage |
---|---|---|
生命周期 | 持久化存储:数据会永久保留,除非被手动清除(通过代码或用户在浏览器设置中清除)。关闭浏览器、重启电脑,甚至操作系统,数据依然存在。没有过期时间的概念。 | 会话级存储:数据只在当前浏览器 会话(Session) 有效。关闭当前标签页或浏览器窗口时,数据立即被清除。刷新页面 (F5 或重新加载)不会清除数据。打开新标签页或新窗口(即使是相同的 URL)会创建一个 新的会话存储空间,数据不共享。 |
作用域 | 同源(Same Origin)且全局共享:在同一源(协议、域名、端口相同)下的所有标签页和浏览器窗口之间共享数据。任何一个标签页写入的数据,其他同源标签页都能立即读取。 | 同源(Same Origin)且独立于标签页/窗口:在同一源下,但每个独立的标签页或窗口都有自己独立的 sessionStorage 实例。一个标签页中设置的 sessionStorage 数据,在另一个(即使是同源的)标签页中无法访问,除非是通过 window.open() 打开的子窗口,在某些情况下可能会继承父窗口的 sessionStorage 引用。 |
存储方式 | 键值对形式存储,所有值都会被转换为字符串。(存储对象或数组需要使用 JSON.stringify() 和 JSON.parse() 进行序列化/反序列化)。 |
键值对形式存储,所有值都会被转换为字符串。(存储对象或数组需要使用 JSON.stringify() 和 JSON.parse() 进行序列化/反序列化)。 |
与服务器交互 | 无。数据完全存储在客户端,不会随 HTTP 请求自动发送到服务器。 | 无。数据完全存储在客户端,不会随 HTTP 请求自动发送到服务器。 |
API 接口 | 相同的 API:localStorage.setItem(key, value) 、 localStorage.getItem(key) 、 localStorage.removeItem(key) 、 localStorage.clear() 、 localStorage.length |
相同的 API:sessionStorage.setItem(key, value) 、 sessionStorage.getItem(key) 、 sessionStorage.removeItem(key) 、 sessionStorage.clear() 、 sessionStorage.length |
典型应用场景 | 用户偏好设置(如主题模式、语言设置)。长期缓存数据(不经常变化的配置、用户登录令牌等非敏感信息)。“记住我”功能(配合其他安全措施)。离线应用数据(Service Worker 配合)。记录用户上次访问状态或关闭前的数据。 | 多步表单数据:用户在填写复杂表单时,分步保存数据,防止刷新丢失。临时购物车:用户在当前会话中添加的商品,关闭标签页即清空。单次会话的页面状态:如筛选条件、分页信息等,仅在当前会话中有效。防止重复提交:在用户提交表单后,设置一个标志位,防止用户在当前会话中重复提交。 |
优缺点总结 | 优点:持久性强,可长期保存数据;容量大。缺点:数据不会自动清理,可能占用过多空间;不适合存储敏感信息(非加密);可能被用户手动清除。 | 优点:临时性强,数据用完即走,自动清理;不同标签页隔离,互不干扰,适用于多任务。缺点:数据不持久;不适合跨标签页共享数据。 |
三、详细解释与代码示例
1. localStorage (本地存储)
localStorage
旨在提供一个可以在用户会话之间保持不变的存储区域。
生命周期(Persistence):
- 永久性:这是它最显著的特点。一旦数据被存储到
localStorage
中,它将一直存在,直到满足以下任一条件:- 通过 JavaScript 代码明确地调用
localStorage.removeItem()
或localStorage.clear()
。 - 用户通过浏览器设置手动清除浏览器数据(例如,清除网站数据、清除缓存等)。
- 网站因安全策略被浏览器删除数据(极少发生)。
- 通过 JavaScript 代码明确地调用
- 独立于会话:关闭浏览器,甚至关闭电脑,再重新打开,之前存储的数据依然在。
作用域(Scope):
- 同源共享:同一个域名、协议和端口下的所有页面(包括不同标签页和窗口)共享相同的
localStorage
数据。这意味着在一个标签页中设置的localStorage
数据,可以立即在另一个同源标签页中被读取和修改。
使用场景:
- 用户偏好设置:例如,网站的主题模式(深色/浅色)、语言偏好、字体大小等。
- 长期缓存:存储一些不经常变动的、但又需要在客户端快速访问的数据,如用户身份验证令牌(请注意安全,不宜存储敏感信息)。
- 离线应用:结合 Service Worker,存储离线应用所需的核心数据。
- “记住我”功能:记住用户的登录状态或用户名,下次访问时无需重新输入(通常需要配合服务器端验证)。
代码示例:
// 1. 存储数据
// 注意:localStorage 只能存储字符串。如果存储对象或数组,需要先进行 JSON 序列化。
localStorage.setItem('username', 'Alice'); // 存储一个字符串
localStorage.setItem('theme', 'dark'); // 存储另一个字符串
const userSettings = {
fontSize: 'medium',
notifications: true
};
localStorage.setItem('settings', JSON.stringify(userSettings)); // 存储对象
// 2. 获取数据
let storedUsername = localStorage.getItem('username'); // "Alice"
console.log("LocalStorage username:", storedUsername);
let storedSettings = localStorage.getItem('settings');
if (storedSettings) {
let parsedSettings = JSON.parse(storedSettings); // 解析为对象
console.log("LocalStorage settings:", parsedSettings); // { fontSize: 'medium', notifications: true }
}
// 3. 删除单条数据
localStorage.removeItem('theme');
console.log("Theme after removal:", localStorage.getItem('theme')); // null
// 4. 清空所有数据 (慎用!)
// localStorage.clear();
// console.log("All data cleared from LocalStorage.");
2. sessionStorage (会话存储)
sessionStorage
旨在为每个独立的浏览器会话提供一个隔离的存储区域。
生命周期(Persistence):
- 会话级别:数据只在当前浏览器会话期间有效。一个会话通常从打开标签页/窗口开始,到关闭该标签页/窗口结束。
- 刷新不清除:在同一个标签页内进行页面刷新(F5、重新加载)不会清除
sessionStorage
数据,因为这仍然被视为同一个会话。 - 关闭即清除:一旦用户关闭了当前标签页或浏览器窗口,所有存储在该会话的
sessionStorage
中的数据都会被自动清除。
作用域(Scope):
- 同源且隔离:虽然也受同源策略限制,但
sessionStorage
更严格:每个独立的标签页或窗口(即使是访问同一网站)都有自己独立的sessionStorage
副本。 - 不共享:你在一个标签页中设置的
sessionStorage
数据,在另一个同源的标签页中无法直接访问。它们是完全隔离的。 window.open()
特殊情况:通过window.open()
方法打开的新窗口,如果与父窗口同源,可能会继承父窗口的sessionStorage
,或者父子窗口之间共享sessionStorage
。但这通常取决于浏览器实现和具体打开方式,不如localStorage
那样明确。
使用场景:
- 多步表单:在用户填写一个需要分多步完成的表单时,可以在每一步保存当前填写的数据,防止用户意外刷新或返回时数据丢失。
- 临时购物车:用户在当前浏览会话中添加的商品,如果关闭标签页,购物车信息就清空。
- 页面状态保持:例如,用户在某个列表页进行了筛选或分页,这些筛选条件可以保存在
sessionStorage
中,当用户从详情页返回列表页时,可以恢复之前的筛选状态。 - 防止重复提交:在用户提交表单后,设置一个标志位,防止用户在当前会话中重复提交(页面刷新后该标志依然存在,但关闭标签页后会清除)。
代码示例:
// 1. 存储数据
sessionStorage.setItem('currentStep', '3'); // 存储当前表单步骤
const tempCart = [
{ id: 'p001', name: 'Laptop', qty: 1 },
{ id: 'p002', name: 'Mouse', qty: 1 }
];
sessionStorage.setItem('cartData', JSON.stringify(tempCart)); // 存储临时购物车数据
// 2. 获取数据
let step = sessionStorage.getItem('currentStep'); // "3"
console.log("SessionStorage current step:", step);
let cartJson = sessionStorage.getItem('cartData');
if (cartJson) {
let cart = JSON.parse(cartJson); // 解析为数组
console.log("SessionStorage cart data:", cart);
}
// 3. 删除单条数据
sessionStorage.removeItem('currentStep');
console.log("Step after removal:", sessionStorage.getItem('currentStep')); // null
// 4. 清空所有数据 (慎用!)
// sessionStorage.clear();
// console.log("All data cleared from SessionStorage.");
四、与 Cookies 的对比
虽然 localStorage
和 sessionStorage
都是 Web Storage API
,但它们经常与传统的 Cookies
进行比较。
特性 / 类别 | Web Storage (localStorage / sessionStorage) | Cookies |
---|---|---|
存储容量 | 大 (5-10 MB) | 小 (约 4KB) |
与服务器交互 | 不参与 HTTP 请求传输,只在客户端操作。 | 每次 HTTP 请求都会自动携带 Cookie 到服务器,增加网络开销。 |
用途 | 主要用于客户端数据存储。 | 主要用于会话管理(用户登录状态)、用户追踪、个性化以及少量客户端数据存储。 |
过期时间 | localStorage 永久;sessionStorage 会话结束即清除。 |
可设置过期时间(会话性或持久性)。 |
易用性 | API 更直观、易用。 | API 相对复杂(直接操作 document.cookie 字符串)。 |
安全性 | 易受 XSS 攻击(JavaScript 可直接访问),不适合存储敏感信息。 | 可以设置 HttpOnly 防止 JavaScript 访问,增强安全性,适合存储会话 ID。 |
五、如何选择?
在开发中,选择 localStorage
还是 sessionStorage
,取决于你对数据生命周期和作用域的需求:
- 需要数据在用户关闭浏览器后依然保留? → 选择
localStorage
。- 例如:用户界面主题、语言设置、记住登录状态(非敏感令牌)。
- 只需要数据在当前标签页/窗口的生命周期内有效,且每个标签页的数据需要隔离? → 选择
sessionStorage
。- 例如:多步表单的临时数据、当前会话的购物车内容、页面筛选状态。
- 需要数据在客户端和服务器之间自动传递(如登录凭证、会话ID)? → 考虑
Cookies
(尤其配合HttpOnly
)。 - 需要存储大量结构化数据,并需要更复杂的查询功能? → 考虑 IndexedDB。
六、重要考量与最佳实践
- 安全性:不要在
localStorage
或sessionStorage
中存储敏感信息(如密码、银行卡号)。它们不提供任何加密机制,并且容易受到跨站脚本(XSS)攻击。敏感数据应始终在服务器端处理和存储。 - 数据类型:它们都只能存储字符串。如果需要存储 JavaScript 对象或数组,务必使用
JSON.stringify()
将其序列化为字符串,并在读取时使用JSON.parse()
反序列化。 - 容量限制:虽然比
Cookies
大,但仍有限制。不要尝试存储过大的文件或数据。 - 阻塞主线程:
localStorage
和sessionStorage
的操作都是同步的。这意味着在读写数据时,会阻塞 JavaScript 主线程,直到操作完成。对于少量数据通常不是问题,但频繁或大量数据的读写可能会导致页面卡顿。 - 用户可控:用户可以随时在浏览器设置中清除
localStorage
和sessionStorage
数据,因此不要完全依赖它们来保存关键信息。