Web 存储对象 localStorage
和 sessionStorage
允许在浏览器中保存键值对。
有趣的是,数据可以在页面刷新(对于 sessionStorage
)甚至浏览器完全重启(对于 localStorage
)后仍然存在。我们很快就会看到这一点。
我们已经有了 cookie。为什么还需要额外的对象呢?
- 与 cookie 不同,Web 存储对象不会在每次请求时发送到服务器。因此,我们可以存储更多数据。大多数现代浏览器允许至少 5 兆字节的数据(或更多),并且具有设置来配置此数据。
- 同样与 cookie 不同,服务器不能通过 HTTP 标头来操作存储对象。所有操作都在 JavaScript 中完成。
- 存储绑定到来源(域名/协议/端口三元组)。也就是说,不同的协议或子域推断出不同的存储对象,它们不能相互访问数据。
这两个存储对象提供相同的方法和属性
setItem(key, value)
– 存储键值对。getItem(key)
– 通过键获取值。removeItem(key)
– 删除键及其值。clear()
– 删除所有内容。key(index)
– 获取给定位置的键。length
– 存储项的数量。
如您所见,它类似于 Map
集合 (setItem/getItem/removeItem
),但也允许使用 key(index)
按索引访问。
让我们看看它是如何工作的。
localStorage 演示
localStorage
的主要功能是
- 在来自同一来源的所有选项卡和窗口之间共享。
- 数据不会过期。它在浏览器重启甚至操作系统重启后仍然存在。
例如,如果您运行此代码…
localStorage.setItem('test', 1);
…然后关闭/打开浏览器或只是在另一个窗口中打开相同的页面,那么您可以像这样获取它
alert( localStorage.getItem('test') ); // 1
我们只需要在同一个来源(域/端口/协议)上,url 路径可以不同。
localStorage
在所有具有相同来源的窗口之间共享,因此如果我们在一个窗口中设置数据,更改将在另一个窗口中可见。
类似对象的访问
我们也可以使用类似普通对象的方式获取/设置键,例如
// set key
localStorage.test = 2;
// get key
alert( localStorage.test ); // 2
// remove key
delete localStorage.test;
这是出于历史原因允许的,并且大部分情况下有效,但通常不建议这样做,因为
-
如果键是用户生成的,它可以是任何东西,例如
length
或toString
,或者localStorage
的另一个内置方法。在这种情况下,getItem/setItem
工作正常,而类似对象的访问失败let key = 'length'; localStorage[key] = 5; // Error, can't assign length
-
有一个
storage
事件,当我们修改数据时会触发。该事件不会发生在类似对象的访问中。我们将在本章后面看到这一点。
遍历键
正如我们所见,这些方法提供了“按键获取/设置/删除”功能。但是如何获取所有保存的值或键呢?
不幸的是,存储对象不可迭代。
一种方法是像遍历数组一样遍历它们
for(let i=0; i<localStorage.length; i++) {
let key = localStorage.key(i);
alert(`${key}: ${localStorage.getItem(key)}`);
}
另一种方法是使用 for key in localStorage
循环,就像我们对普通对象一样。
它遍历键,但也输出一些我们不需要的内置字段
// bad try
for(let key in localStorage) {
alert(key); // shows getItem, setItem and other built-in stuff
}
…所以我们需要使用 hasOwnProperty
检查来过滤原型中的字段
for(let key in localStorage) {
if (!localStorage.hasOwnProperty(key)) {
continue; // skip keys like "setItem", "getItem" etc
}
alert(`${key}: ${localStorage.getItem(key)}`);
}
…或者只使用 Object.keys
获取“自己的”键,然后根据需要遍历它们
let keys = Object.keys(localStorage);
for(let key of keys) {
alert(`${key}: ${localStorage.getItem(key)}`);
}
后者有效,因为 Object.keys
只返回属于该对象的键,忽略原型。
仅字符串
请注意,键和值都必须是字符串。
如果它们是其他类型,例如数字或对象,它们将自动转换为字符串。
localStorage.user = {name: "John"};
alert(localStorage.user); // [object Object]
我们可以使用JSON
来存储对象。
localStorage.user = JSON.stringify({name: "John"});
// sometime later
let user = JSON.parse( localStorage.user );
alert( user.name ); // John
也可以将整个存储对象字符串化,例如用于调试目的。
// added formatting options to JSON.stringify to make the object look nicer
alert( JSON.stringify(localStorage, null, 2) );
sessionStorage
sessionStorage
对象的使用频率远低于 localStorage
。
属性和方法相同,但限制更多。
sessionStorage
仅存在于当前浏览器标签页中。- 另一个具有相同页面的标签页将拥有不同的存储。
- 但它在同一标签页中的 iframe 之间共享(假设它们来自相同的来源)。
- 数据在页面刷新后仍然存在,但在关闭/打开标签页后则不存在。
让我们看看实际操作。
运行这段代码…
sessionStorage.setItem('test', 1);
…然后刷新页面。现在您仍然可以获取数据。
alert( sessionStorage.getItem('test') ); // after refresh: 1
…但是,如果您在另一个标签页中打开相同的页面,然后再次尝试,上面的代码将返回 null
,表示“未找到”。
这正是因为 sessionStorage
不仅绑定到来源,还绑定到浏览器标签页。因此,sessionStorage
的使用非常有限。
存储事件
当 localStorage
或 sessionStorage
中的数据更新时,存储 事件将触发,并具有以下属性:
key
– 已更改的键(如果调用.clear()
,则为null
)。oldValue
– 旧值(如果键是新添加的,则为null
)。newValue
– 新值(如果键被删除,则为null
)。url
– 发生更新的文档的 URL。storageArea
– 发生更新的localStorage
或sessionStorage
对象。
重要的是:该事件将在所有可以访问存储的 window
对象上触发,除了导致该事件的 window
对象。
让我们详细说明。
假设您有两个窗口,每个窗口都包含相同的网站。因此,localStorage
在它们之间共享。
您可能希望在两个浏览器窗口中打开此页面以测试下面的代码。
如果两个窗口都监听 window.onstorage
,那么每个窗口都会对另一个窗口中发生的更新做出反应。
// triggers on updates made to the same storage from other documents
window.onstorage = event => { // can also use window.addEventListener('storage', event => {
if (event.key != 'now') return;
alert(event.key + ':' + event.newValue + " at " + event.url);
};
localStorage.setItem('now', Date.now());
请注意,该事件还包含:event.url
– 更新数据的文档的 URL。
此外,event.storageArea
包含存储对象 – 该事件对于 sessionStorage
和 localStorage
都是相同的,因此 event.storageArea
引用了被修改的对象。我们甚至可能希望在其中设置一些内容,以“响应”更改。
这允许来自相同来源的不同窗口交换消息。
现代浏览器还支持 广播通道 API,这是一个用于相同来源的窗口间通信的专用 API,它功能更强大,但支持度较低。有一些库基于 localStorage
对该 API 进行填充,使其在任何地方都可用。
总结
Web 存储对象 localStorage
和 sessionStorage
允许在浏览器中存储键值对。
key
和value
都必须是字符串。- 限制为 5mb+,取决于浏览器。
- 它们不会过期。
- 数据绑定到源(域/端口/协议)。
localStorage |
sessionStorage |
---|---|
在具有相同源的所有选项卡和窗口之间共享 | 在浏览器选项卡内可见,包括来自相同源的 iframe |
浏览器重启后仍然存在 | 页面刷新后仍然存在(但关闭选项卡后消失) |
API
setItem(key, value)
– 存储键值对。getItem(key)
– 通过键获取值。removeItem(key)
– 删除键及其值。clear()
– 删除所有内容。key(index)
– 获取键号index
。length
– 存储项的数量。- 使用
Object.keys
获取所有键。 - 我们以对象属性的方式访问键,在这种情况下,
storage
事件不会触发。
存储事件
- 在
setItem
、removeItem
、clear
调用时触发。 - 包含有关操作的所有数据(
key/oldValue/newValue
)、文档url
和存储对象storageArea
。 - 在所有可以访问存储的
window
对象上触发,除了生成它的那个对象(对于sessionStorage
,在选项卡内;对于localStorage
,在全局范围内)。
评论
<code>
标签;对于多行代码,请将它们包装在<pre>
标签中;对于超过 10 行的代码,请使用沙箱(plnkr、jsbin、codepen…)。