第 31 章 客户端存储
第 31 章 客户端存储
网页关闭后,数据还在吗?JavaScript 有几种方式可以把数据存在浏览器里,这就是"客户端存储"。
31.1 Cookie
特点:约 4KB / 自动发送 / 同源策略
Cookie 是最早期的客户端存储方案,有点像"便利店的小票"——每次你去(请求服务器),店员都会看看你手里的小票(Cookie),记住你之前买过什么。
1
2
3
4
| // Cookie 的限制
// 1. 大小限制:约 4KB
// 2. 自动发送:每个请求都会带上
// 3. 同源策略:只能访问同源的 Cookie
|
document.cookie:读写同一属性(写入追加不覆盖)
1
2
3
4
5
6
7
8
9
| // 读取所有 Cookie
console.log(document.cookie);
// 写入 Cookie(注意:是追加,不是覆盖!)
document.cookie = 'name=小明';
document.cookie = 'age=18';
document.cookie = 'city=北京';
console.log(document.cookie);
// 打印结果: name=小明; age=18; city=北京
|
属性:expires / path / domain / secure / HttpOnly
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // 设置过期时间(UTC 时间格式)
document.cookie = 'session=abc123; expires=Thu, 31 Dec 2024 23:59:59 GMT';
// 设置路径
document.cookie = 'name=小明; path=/;';
// 设置域
document.cookie = 'name=小明; domain=example.com';
// 安全标志(只能通过 HTTPS 传输)
document.cookie = 'secure_cookie=value; secure';
// HttpOnly 标志(只能通过 HTTP 访问,JavaScript 无法访问)
// 这个只能通过服务器设置
|
读取与删除 Cookie
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| // 读取指定名称的 Cookie
function getCookie(name) {
const cookies = document.cookie.split('; ');
for (const cookie of cookies) {
const [key, value] = cookie.split('=');
if (key === name) {
return value;
}
}
return null;
}
console.log(getCookie('name')); // 打印结果: 小明
// 删除 Cookie(设置过期时间为过去的时间)
function deleteCookie(name) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
}
deleteCookie('name');
|
下一节,我们来学习 Web Storage!
31.2 Web Storage
localStorage:永不过期 / 约 5MB / 同源
localStorage 就像一个"永久仓库"——只要你不动它,数据就会一直保存着。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| // 设置数据
localStorage.setItem('name', '小明');
localStorage.setItem('age', '18');
// 读取数据
console.log(localStorage.getItem('name')); // 打印结果: 小明
// 删除数据
localStorage.removeItem('age');
// 清空所有数据
localStorage.clear();
// 获取所有 key
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
console.log(key + ': ' + value);
}
|
sessionStorage:会话结束自动清除
sessionStorage 就像一个"临时储物柜"——浏览器关了,数据就没了。
1
2
3
4
5
6
7
8
9
10
| // 设置数据(会话结束时自动清除)
sessionStorage.setItem('tempData', '临时数据');
// 读取数据
console.log(sessionStorage.getItem('tempData')); // 打印结果: 临时数据
// 删除数据
sessionStorage.removeItem('tempData');
// 关闭浏览器标签页后,数据就清除了
|
setItem / getItem / removeItem / clear / key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // setItem:设置
localStorage.setItem('key1', 'value1');
// getItem:获取
const value = localStorage.getItem('key1');
// removeItem:删除
localStorage.removeItem('key1');
// clear:清空
localStorage.clear();
// key:获取指定索引的 key
const firstKey = localStorage.key(0);
|
localStorage 只能存字符串的坑
1
2
3
4
5
6
7
8
9
| // ❌ 直接存对象,会变成 [object Object]
const user = { name: '小明', age: 18 };
localStorage.setItem('user', user);
console.log(localStorage.getItem('user')); // 打印结果: [object Object]
// ✅ 正确做法:转成 JSON
localStorage.setItem('user', JSON.stringify(user));
const storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser.name); // 打印结果: 小明
|
storage 事件:跨标签页通信
1
2
3
4
5
6
7
8
9
| // 标签页 A
localStorage.setItem('message', 'Hello from tab A!');
// 标签页 B(在同一个域下)
window.addEventListener('storage', function(event) {
console.log('key:', event.key);
console.log('newValue:', event.newValue);
console.log('oldValue:', event.oldValue);
});
|
下一节,我们来学习 IndexedDB!
31.3 IndexedDB
概念:浏览器端 NoSQL 数据库
IndexedDB 是浏览器里的"数据库",可以存储大量结构化数据,比 localStorage 强大得多。
1
2
3
4
5
| // IndexedDB 的特点
// 1. 容量大:可以存储几百 MB 甚至 GB 的数据
// 2. 支持索引:可以快速查询
// 3. 支持事务:保证数据一致性
// 4. 异步 API:不会阻塞主线程
|
核心概念:数据库 / 对象仓库 / 事务 / 索引
1
2
3
4
| // 数据库(Database):最大的容器
// 对象仓库(Object Store):类似数据库的"表"
// 事务(Transaction):保证操作的原子性
// 索引(Index):加速查询
|
打开数据库:indexedDB.open() / onupgradeneeded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // 打开数据库
const request = indexedDB.open('myDatabase', 1);
request.onupgradeneeded = function(event) {
const db = event.target.result;
// 创建对象仓库
const store = db.createObjectStore('users', { keyPath: 'id' });
// 创建索引
store.createIndex('name', 'name', { unique: false });
store.createIndex('email', 'email', { unique: true });
};
request.onsuccess = function(event) {
const db = event.target.result;
console.log('数据库打开成功');
};
request.onerror = function(event) {
console.log('数据库打开失败');
};
|
对象仓库主键:keyPath / autoIncrement
1
2
3
4
5
| // keyPath:使用对象的某个属性作为主键
db.createObjectStore('users', { keyPath: 'id' });
// autoIncrement:自动生成数字主键
db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
|
增删改查:add / put / get / delete / getAll / clear
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| // 在事务中进行操作
function addUser(db, user) {
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
// 添加数据
const request = store.add(user);
request.onsuccess = function() {
console.log('用户添加成功');
};
}
// 读取数据
function getUser(db, id) {
const transaction = db.transaction(['users'], 'readonly');
const store = transaction.objectStore('users');
const request = store.get(id);
request.onsuccess = function() {
console.log('用户信息:', request.result);
};
}
// 更新数据(如果 key 已存在则更新)
function updateUser(db, user) {
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
store.put(user);
}
// 删除数据
function deleteUser(db, id) {
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
store.delete(id);
}
// 获取所有数据
function getAllUsers(db) {
const transaction = db.transaction(['users'], 'readonly');
const store = transaction.objectStore('users');
const request = store.getAll();
request.onsuccess = function() {
console.log('所有用户:', request.result);
};
}
// 清空仓库
function clearUsers(db) {
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
store.clear();
}
|
本章小结
本章我们学习了客户端存储:
- Cookie:约 4KB,自动发送,适合少量数据。
- Web Storage:localStorage 永不过期,sessionStorage 会话结束清除,只能存字符串。
- IndexedDB:浏览器端数据库,支持大量数据、索引、事务。
下一章,我们要学习 Proxy 与 Reflect——JavaScript 的"拦截器"!