W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
Web 存儲(chǔ)對(duì)象 ?localStorage
? 和 ?sessionStorage
? 允許我們?cè)跒g覽器上保存鍵/值對(duì)。
它們有趣的是,在頁(yè)面刷新后(對(duì)于 sessionStorage
)甚至瀏覽器完全重啟(對(duì)于 localStorage
)后,數(shù)據(jù)仍然保留在瀏覽器中。我們很快就會(huì)看到。
我們已經(jīng)有了 cookie。為什么還要其他存儲(chǔ)對(duì)象呢?
兩個(gè)存儲(chǔ)對(duì)象都提供相同的方法和屬性:
setItem(key, value)
? —— 存儲(chǔ)鍵/值對(duì)。getItem(key)
? —— 按照鍵獲取值。removeItem(key)
? —— 刪除鍵及其對(duì)應(yīng)的值。clear()
? —— 刪除所有數(shù)據(jù)。key(index)
? —— 獲取該索引下的鍵名。length
? —— 存儲(chǔ)的內(nèi)容的長(zhǎng)度。正如你所看到的,它就像一個(gè) Map
集合(setItem/getItem/removeItem
),但也允許通過(guò) key(index)
來(lái)按索引訪問(wèn)。
讓我們看看它是如何工作的吧。
localStorage
最主要的特點(diǎn)是:
例如,如果你運(yùn)行此代碼……
localStorage.setItem('test', 1);
……然后關(guān)閉/重新打開(kāi)瀏覽器,或者只是在不同的窗口打開(kāi)同一頁(yè)面,然后你可以這樣獲取它:
alert( localStorage.getItem('test') ); // 1
我們只需要在同一個(gè)源(域/端口/協(xié)議),URL 路徑可以不同。
在所有同源的窗口之間,localStorage
數(shù)據(jù)可以共享。因此,如果我們?cè)谝粋€(gè)窗口中設(shè)置了數(shù)據(jù),則在另一個(gè)窗口中也可以看到數(shù)據(jù)變化。
我們還可以像使用一個(gè)普通對(duì)象那樣,讀取/設(shè)置鍵,像這樣:
// 設(shè)置 key
localStorage.test = 2;
// 獲取 key
alert( localStorage.test ); // 2
// 刪除 key
delete localStorage.test;
這是歷史原因造成的,并且大多數(shù)情況下都可行,但通常不建議這樣做,因?yàn)椋?
length
或 toString
,也可以是 localStorage
的另一種內(nèi)建方法。在這種情況下,getItem/setItem
可以正常工作,而類(lèi)對(duì)象訪問(wèn)的方式則會(huì)失敗:let key = 'length';
localStorage[key] = 5; // Error,無(wú)法對(duì) length 進(jìn)行賦值
storage
? 事件,在我們更改數(shù)據(jù)時(shí)會(huì)觸發(fā)。但以類(lèi)對(duì)象方式訪問(wèn)時(shí),不會(huì)觸發(fā)該事件。我們將在本章的后面看到。正如我們所看到的,這些方法提供了“按照鍵獲取/設(shè)置/刪除”的功能。但我們?nèi)绾潍@取所有保存的值或鍵呢?
不幸的是,存儲(chǔ)對(duì)象是不可迭代的。
一種方法是像遍歷數(shù)組那樣遍歷它們:
for(let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
alert(`${key}: ${localStorage.getItem(key)}`);
}
另一個(gè)方式是使用 for key in localStorage
循環(huán),就像處理常規(guī)對(duì)象一樣。
它會(huì)遍歷所有的鍵,但也會(huì)輸出一些我們不需要的內(nèi)建字段。
// 不好的嘗試
for(let key in localStorage) {
alert(key); // 顯示 getItem,setItem 和其他內(nèi)建的東西
}
……因此,我們需要使用 hasOwnProperty
檢查來(lái)過(guò)濾掉原型中的字段:
for(let key in localStorage) {
if (!localStorage.hasOwnProperty(key)) {
continue; // 跳過(guò)像 "setItem","getItem" 等這樣的鍵
}
alert(`${key}: ${localStorage.getItem(key)}`);
}
……或者,使用 Object.keys
獲取只屬于“自己”的鍵,然后如果需要,可以遍歷它們:
let keys = Object.keys(localStorage);
for(let key of keys) {
alert(`${key}: ${localStorage.getItem(key)}`);
}
后者有效,因?yàn)?nbsp;Object.keys
只返回屬于對(duì)象的鍵,會(huì)忽略原型上的。
請(qǐng)注意,鍵和值都必須是字符串。
如果是任何其他類(lèi)型,例數(shù)字或?qū)ο?,它?huì)被自動(dòng)轉(zhuǎn)換為字符串。
localStorage.user = {name: "John"};
alert(localStorage.user); // [object Object]
我們可以使用 JSON
來(lái)存儲(chǔ)對(duì)象:
localStorage.user = JSON.stringify({name: "John"});
// sometime later
let user = JSON.parse( localStorage.user );
alert( user.name ); // John
也可以對(duì)整個(gè)存儲(chǔ)對(duì)象進(jìn)行字符串化處理,例如出于調(diào)試目的:
// 為 JSON.stringify 增加了格式設(shè)置選項(xiàng),以使對(duì)象看起來(lái)更美觀
alert( JSON.stringify(localStorage, null, 2) );
sessionStorage
對(duì)象的使用頻率比 localStorage
對(duì)象低得多。
屬性和方法是相同的,但是它有更多的限制:
sessionStorage
? 的數(shù)據(jù)只存在于當(dāng)前瀏覽器標(biāo)簽頁(yè)。讓我們看看它的運(yùn)行效果。
運(yùn)行此代碼……
sessionStorage.setItem('test', 1);
……然后刷新頁(yè)面。這時(shí)你仍然可以獲取到數(shù)據(jù):
alert( sessionStorage.getItem('test') ); // after refresh: 1
……但是,如果你在另一個(gè)新的標(biāo)簽頁(yè)中打開(kāi)此頁(yè)面,然后在新頁(yè)面中再次運(yùn)行上面這行代碼,則會(huì)得到 null
,表示“未找到數(shù)據(jù)”。
這是因?yàn)?nbsp;sessionStorage
不僅綁定到源,還綁定在同一瀏覽器標(biāo)簽頁(yè)。因此,sessionStorage
很少被使用。
當(dāng) localStorage
或 sessionStorage
中的數(shù)據(jù)更新后,storage 事件就會(huì)觸發(fā),它具有以下屬性:
key
? —— 發(fā)生更改的數(shù)據(jù)的 ?key
?(如果調(diào)用的是 ?.clear()
? 方法,則為 ?null
?)。oldValue
? —— 舊值(如果是新增數(shù)據(jù),則為 ?null
?)。newValue
? —— 新值(如果是刪除數(shù)據(jù),則為 ?null
?)。url
? —— 發(fā)生數(shù)據(jù)更新的文檔的 url。storageArea
? —— 發(fā)生數(shù)據(jù)更新的 ?localStorage
? 或 ?sessionStorage
? 對(duì)象。重要的是:該事件會(huì)在所有可訪問(wèn)到存儲(chǔ)對(duì)象的 window
對(duì)象上觸發(fā),導(dǎo)致當(dāng)前數(shù)據(jù)改變的 window
對(duì)象除外。
我們來(lái)詳細(xì)解釋一下。
想象一下,你有兩個(gè)窗口,它們具有相同的頁(yè)面。所以 localStorage
在它們之間是共享的。
你可以想在瀏覽器的兩個(gè)窗口中打開(kāi)此頁(yè)面來(lái)測(cè)試下面的代碼。
如果兩個(gè)窗口都在監(jiān)聽(tīng) window.onstorage
事件,那么每個(gè)窗口都會(huì)對(duì)另一個(gè)窗口中發(fā)生的更新作出反應(yīng)。
// 在其他文檔對(duì)同一存儲(chǔ)進(jìn)行更新時(shí)觸發(fā)
window.onstorage = event => { // 也可以使用 window.addEventListener('storage', event => {
if (event.key != 'now') return;
alert(event.key + ':' + event.newValue + " at " + event.url);
};
localStorage.setItem('now', Date.now());
請(qǐng)注意,該事件還包含:event.url
—— 發(fā)生數(shù)據(jù)更新的文檔的 url。
并且,event.storageArea
包含存儲(chǔ)對(duì)象 —— sessionStorage
和 localStorage
具有相同的事件,所以 event.storageArea
引用了被修改的對(duì)象。我們可能會(huì)想設(shè)置一些東西,以“響應(yīng)”更改。
這允許同源的不同窗口交換消息。
現(xiàn)代瀏覽器還支持 Broadcast channel API,這是用于同源窗口之間通信的特殊 API,它的功能更全,但被支持的情況不好。有一些庫(kù)基于 localStorage
來(lái) polyfill 該 API,使其可以用在任何地方。
Web 存儲(chǔ)對(duì)象 ?localStorage
? 和 ?sessionStorage
? 允許我們?cè)跒g覽器中保存鍵/值對(duì)。
key
? 和 ?value
? 都必須為字符串。localStorage
|
sessionStorage
|
---|---|
在同源的所有標(biāo)簽頁(yè)和窗口之間共享數(shù)據(jù) | 在當(dāng)前瀏覽器標(biāo)簽頁(yè)中可見(jiàn),包括同源的 iframe |
瀏覽器重啟后數(shù)據(jù)仍然保留 | 頁(yè)面刷新后數(shù)據(jù)仍然保留(但標(biāo)簽頁(yè)關(guān)閉后數(shù)據(jù)則不再保留) |
API:
setItem(key, value)
? —— 存儲(chǔ)鍵/值對(duì)。getItem(key)
? —— 按照鍵獲取值。removeItem(key)
? —— 刪除鍵及其對(duì)應(yīng)的值。clear()
? —— 刪除所有數(shù)據(jù)。key(index)
? —— 獲取該索引下的鍵名。length
? —— 存儲(chǔ)的內(nèi)容的長(zhǎng)度。Object.keys
? 來(lái)獲取所有的鍵。storage
? 事件。Storage 事件:
setItem
?,?removeItem
?,?clear
? 方法后觸發(fā)。key/oldValue/newValue
?),文檔 ?url
? 和存儲(chǔ)對(duì)象 ?storageArea
?。window
? 對(duì)象上觸發(fā),導(dǎo)致當(dāng)前數(shù)據(jù)改變的 ?window
? 對(duì)象除外(對(duì)于 ?sessionStorage
? 是在當(dāng)前標(biāo)簽頁(yè)下,對(duì)于 ?localStorage
? 是在全局,即所有同源的窗口)。創(chuàng)建一個(gè) textarea
字段,每當(dāng)其值發(fā)生變化時(shí),可以將其“自動(dòng)保存”。
因此,如果用戶(hù)不小心關(guān)閉了頁(yè)面,然后重新打開(kāi),他會(huì)發(fā)現(xiàn)之前未完成的輸入仍然保留在那里。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: