JavaScript本地存储
什么是本地存储?
本地存储是指在浏览器中存储数据的能力,这些数据保存在用户的设备上,不需要服务器参与。JavaScript提供了多种本地存储方式,其中最常用的是LocalStorage和SessionStorage。
本地存储的主要优点包括:
- 数据持久化:数据可以在浏览器关闭后仍然保留
- 减少网络请求:可以将频繁使用的数据存储在本地,减少服务器请求
- 提高性能:本地读取数据比网络请求更快
- 离线支持:即使在离线状态下,也可以访问存储的数据
LocalStorage
LocalStorage是一种持久化的本地存储方式,数据存储在浏览器中,不会随着浏览器窗口关闭而删除,除非手动清除。
LocalStorage的特点
- 数据以键值对的形式存储
- 数据大小限制:通常为5MB左右
- 同源策略:只有同一个域名下的页面可以访问存储的数据
- 数据类型:只能存储字符串类型,其他类型需要手动转换
- 持久化存储:数据不会过期,除非手动删除
LocalStorage的基本操作
设置数据
使用setItem()方法设置数据,参数为键名和键值。
// 存储字符串
localStorage.setItem('username', 'John');
// 存储数字
localStorage.setItem('age', '30');
// 存储对象(需要转换为字符串)
const user = { name: 'John', age: 30 };
localStorage.setItem('user', JSON.stringify(user));
// 存储数组(需要转换为字符串)
const hobbies = ['reading', 'coding', 'traveling'];
localStorage.setItem('hobbies', JSON.stringify(hobbies));获取数据
使用getItem()方法获取数据,参数为键名。
// 获取字符串
const username = localStorage.getItem('username');
console.log(username); // John
// 获取数字(需要转换为数字类型)
const age = parseInt(localStorage.getItem('age'));
console.log(age); // 30
// 获取对象(需要转换为对象类型)
const user = JSON.parse(localStorage.getItem('user'));
console.log(user.name); // John
// 获取数组(需要转换为数组类型)
const hobbies = JSON.parse(localStorage.getItem('hobbies'));
console.log(hobbies[0]); // reading删除数据
使用removeItem()方法删除指定键名的数据。
// 删除单个数据
localStorage.removeItem('age');清空所有数据
使用clear()方法清空所有存储的数据。
// 清空所有数据
localStorage.clear();获取所有键名
使用key()方法获取指定索引的键名,结合length属性可以遍历所有键名。
// 遍历所有键值对
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
console.log(`${key}: ${value}`);
}SessionStorage
SessionStorage是一种会话级别的本地存储方式,数据存储在浏览器中,当浏览器窗口关闭时,数据会被自动删除。
SessionStorage的特点
- 数据以键值对的形式存储
- 数据大小限制:通常为5MB左右
- 同源策略:只有同一个域名下的页面可以访问存储的数据
- 数据类型:只能存储字符串类型,其他类型需要手动转换
- 会话级存储:数据在浏览器窗口关闭时自动删除
- 标签页隔离:不同标签页之间的数据不共享
SessionStorage的基本操作
SessionStorage的API与LocalStorage完全相同,只是存储的生命周期不同。
// 设置数据
sessionStorage.setItem('sessionId', '12345');
// 获取数据
const sessionId = sessionStorage.getItem('sessionId');
console.log(sessionId); // 12345
// 删除数据
sessionStorage.removeItem('sessionId');
// 清空所有数据
sessionStorage.clear();LocalStorage与SessionStorage的区别
| 特性 | LocalStorage | SessionStorage |
|---|---|---|
| 存储生命周期 | 持久化,除非手动删除 | 会话级,窗口关闭后删除 |
| 跨标签页共享 | 是 | 否 |
| 数据大小 | 约5MB | 约5MB |
| API | 相同 | 相同 |
| 适用场景 | 长期存储的数据,如用户偏好设置 | 临时数据,如表单数据、会话ID |
本地存储的使用场景
1. 用户偏好设置
// 保存用户主题偏好
function saveThemePreference(theme) {
localStorage.setItem('theme', theme);
}
// 获取用户主题偏好
function getThemePreference() {
return localStorage.getItem('theme') || 'light';
}
// 应用主题偏好
const theme = getThemePreference();
document.body.className = `theme-${theme}`;2. 表单数据缓存
// 保存表单数据
document.addEventListener('input', (event) => {
const { name, value } = event.target;
const formData = JSON.parse(localStorage.getItem('formData') || '{}');
formData[name] = value;
localStorage.setItem('formData', JSON.stringify(formData));
});
// 恢复表单数据
window.addEventListener('DOMContentLoaded', () => {
const formData = JSON.parse(localStorage.getItem('formData') || '{}');
Object.entries(formData).forEach(([name, value]) => {
const input = document.querySelector(`[name="${name}"]`);
if (input) {
input.value = value;
}
});
});3. 缓存API响应
// 缓存API响应
async function fetchData(url, cacheKey) {
// 检查缓存是否存在
const cachedData = localStorage.getItem(cacheKey);
if (cachedData) {
console.log('使用缓存数据');
return JSON.parse(cachedData);
}
// 发送网络请求
console.log('发送网络请求');
const response = await fetch(url);
const data = await response.json();
// 缓存数据
localStorage.setItem(cacheKey, JSON.stringify(data));
return data;
}
// 使用示例
fetchData('https://api.example.com/data', 'api-data')
.then(data => {
console.log(data);
});4. 购物车数据
// 添加商品到购物车
function addToCart(product) {
const cart = JSON.parse(localStorage.getItem('cart') || '[]');
cart.push(product);
localStorage.setItem('cart', JSON.stringify(cart));
}
// 获取购物车数据
function getCart() {
return JSON.parse(localStorage.getItem('cart') || '[]');
}
// 清空购物车
function clearCart() {
localStorage.removeItem('cart');
}本地存储的限制和注意事项
1. 数据类型限制
本地存储只能存储字符串类型的数据,其他类型(如对象、数组、数字)需要手动转换。
// 错误:直接存储对象
localStorage.setItem('user', { name: 'John' }); // 存储结果为 "[object Object]"
// 正确:先转换为字符串
localStorage.setItem('user', JSON.stringify({ name: 'John' }));2. 数据大小限制
本地存储的大小通常限制为5MB左右,超过这个限制会抛出错误。
// 检查存储大小
function checkStorageSize() {
let totalSize = 0;
for (let key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
totalSize += localStorage[key].length;
}
}
console.log(`当前存储大小:${totalSize} 字节`);
return totalSize;
}3. 同源策略
本地存储遵循同源策略,只有同一个域名、协议和端口下的页面可以访问存储的数据。
4. 安全性问题
本地存储中的数据是明文存储的,不适合存储敏感信息,如密码、信用卡信息等。
// 不推荐:存储敏感信息
localStorage.setItem('password', '123456');
localStorage.setItem('creditCard', '1234-5678-9012-3456');5. 性能问题
频繁读写本地存储会影响性能,尤其是在循环中。
// 不推荐:频繁写入本地存储
for (let i = 0; i < 1000; i++) {
localStorage.setItem(`item-${i}`, i);
}
// 推荐:批量处理,减少写入次数
const items = {};
for (let i = 0; i < 1000; i++) {
items[`item-${i}`] = i;
}
localStorage.setItem('items', JSON.stringify(items));本地存储的最佳实践
- 只存储必要的数据:避免存储大量数据,只存储频繁使用的数据
- 定期清理过期数据:对于有过期时间的数据,定期检查并清理
- 使用合适的存储方式:根据数据的生命周期选择LocalStorage或SessionStorage
- 加密敏感数据:如果必须存储敏感数据,使用加密算法加密后再存储
- 错误处理:添加错误处理代码,防止存储失败导致应用崩溃
- 数据验证:从本地存储读取数据后,进行验证,确保数据格式正确
- 批量操作:减少读写次数,提高性能
- 使用命名空间:为不同功能的数据添加前缀,避免键名冲突
本地存储的替代方案
1. IndexedDB
IndexedDB是一种更强大的本地存储方案,适合存储大量结构化数据。
2. Cookies
Cookies也可以用于本地存储,但它们有以下限制:
- 数据大小限制:约4KB
- 每次请求都会发送到服务器
- 可以设置过期时间
3. Cache API
Cache API主要用于缓存HTTP请求和响应,是Service Worker的一部分,用于实现离线功能。
示例:完整的本地存储应用
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>本地存储示例</title>
<style>
.dark-theme {
background-color: #333;
color: #fff;
}
.light-theme {
background-color: #fff;
color: #333;
}
</style>
</head>
<body class="light-theme">
<h1>本地存储示例</h1>
<h2>主题切换</h2>
<button id="light-theme-btn">浅色主题</button>
<button id="dark-theme-btn">深色主题</button>
<h2>表单数据缓存</h2>
<form id="example-form">
<div>
<label for="name">姓名:</label>
<input type="text" id="name" name="name">
</div>
<div>
<label for="email">邮箱:</label>
<input type="email" id="email" name="email">
</div>
<div>
<label for="message">留言:</label>
<textarea id="message" name="message" rows="3"></textarea>
</div>
<button type="submit">提交</button>
<button type="button" id="clear-form">清空表单</button>
</form>
<script>
// 主题切换功能
const lightThemeBtn = document.getElementById('light-theme-btn');
const darkThemeBtn = document.getElementById('dark-theme-btn');
const body = document.body;
// 加载主题偏好
const savedTheme = localStorage.getItem('theme') || 'light';
body.className = `${savedTheme}-theme`;
// 切换到浅色主题
lightThemeBtn.addEventListener('click', () => {
body.className = 'light-theme';
localStorage.setItem('theme', 'light');
});
// 切换到深色主题
darkThemeBtn.addEventListener('click', () => {
body.className = 'dark-theme';
localStorage.setItem('theme', 'dark');
});
// 表单数据缓存功能
const form = document.getElementById('example-form');
const clearFormBtn = document.getElementById('clear-form');
// 加载表单数据
const savedFormData = JSON.parse(localStorage.getItem('formData') || '{}');
Object.entries(savedFormData).forEach(([name, value]) => {
const input = form.querySelector(`[name="${name}"]`);
if (input) {
input.value = value;
}
});
// 监听表单输入,保存数据
form.addEventListener('input', (event) => {
const { name, value } = event.target;
const formData = JSON.parse(localStorage.getItem('formData') || '{}');
formData[name] = value;
localStorage.setItem('formData', JSON.stringify(formData));
});
// 提交表单,清除缓存
form.addEventListener('submit', (event) => {
event.preventDefault();
localStorage.removeItem('formData');
alert('表单提交成功!');
form.reset();
});
// 清空表单和缓存
clearFormBtn.addEventListener('click', () => {
localStorage.removeItem('formData');
form.reset();
});
</script>
</body>
</html>总结
本地存储是JavaScript中非常有用的功能,允许在浏览器中存储数据,提供了持久化存储和会话级存储两种方式。LocalStorage适用于需要长期保存的数据,而SessionStorage适用于临时数据。
在使用本地存储时,需要注意数据类型限制、大小限制、同源策略和安全性问题。通过遵循最佳实践,可以充分利用本地存储的优势,同时避免潜在的问题。
本地存储广泛应用于用户偏好设置、表单数据缓存、API响应缓存、购物车数据等场景,是现代Web应用中不可或缺的一部分。
练习
实现一个简单的待办事项列表,使用LocalStorage保存数据,包括添加、删除和标记完成功能。
实现一个主题切换功能,支持浅色主题和深色主题,使用LocalStorage保存用户偏好。
实现一个表单数据自动保存功能,当用户输入表单数据时,自动保存到LocalStorage,页面刷新后可以恢复。
实现一个简单的API响应缓存功能,将API响应缓存到LocalStorage,下次请求时如果缓存存在且未过期,则直接使用缓存数据。
实现一个购物车功能,使用LocalStorage保存购物车数据,包括添加商品、删除商品、修改商品数量和清空购物车功能。