網頁儲存物件 localStorage
和 sessionStorage
允許在瀏覽器中儲存金鑰/值對。
它們有趣的地方在於,這些資料可以在頁面重新整理(對於 sessionStorage
)甚至瀏覽器完全重新啟動(對於 localStorage
)後仍然存在。我們很快就會看到。
我們已經有 Cookie 了。為什麼需要額外的物件?
- 與 Cookie 不同,網頁儲存物件不會在每次要求時傳送至伺服器。因此,我們可以儲存更多資料。大多數現代瀏覽器允許至少 5 MB 的資料(或更多),並有設定可以設定這些資料。
- 與 Cookie 不同的是,伺服器無法透過 HTTP 標頭來操作儲存物件。所有操作都必須透過 JavaScript 執行。
- 儲存空間與來源 (網域/通訊協定/埠號三元組) 相關。也就是說,不同的通訊協定或次網域會產生不同的儲存物件,它們無法彼此存取資料。
兩種儲存物件都提供相同的函式和屬性
setItem(key, value)
– 儲存 key/value 成對資料。getItem(key)
– 透過 key 取得 value。removeItem(key)
– 移除 key 及其 value。clear()
– 刪除所有資料。key(index)
– 取得指定位置的 key。length
– 已儲存項目數。
如你所見,它就像一個 Map
集合 (setItem/getItem/removeItem
),但也可以透過 key(index)
根據索引來存取。
讓我們看看它是如何運作的。
localStorage 示範
localStorage
的主要功能為
- 在來自相同來源的所有分頁和視窗之間共用。
- 資料不會過期。它會在瀏覽器重新啟動,甚至作業系統重新開機後仍然存在。
例如,如果你執行這段程式碼…
localStorage.setItem('test', 1);
…然後關閉/開啟瀏覽器,或是在不同的視窗中開啟同一頁面,你就可以像這樣取得資料
alert( localStorage.getItem('test') ); // 1
我們只需要在相同的來源 (網域/埠號/通訊協定) 中,網址路徑可以不同。
localStorage
在所有具有相同來源的視窗之間共用,因此如果我們在一個視窗中設定資料,變更會在另一個視窗中顯示出來。
類似物件的存取
我們也可以使用一般物件的方式來取得/設定 key,如下所示
// set key
localStorage.test = 2;
// get key
alert( localStorage.test ); // 2
// remove key
delete localStorage.test;
由於歷史原因,這種方式是被允許的,而且大多數情況下都能正常運作,但通常不建議使用,因為
-
如果 key 是使用者產生的,它可以是任何東西,例如
length
或toString
,或是localStorage
的另一個內建函式。在這種情況下,getItem/setItem
可以正常運作,但類似物件的存取會失敗let key = 'length'; localStorage[key] = 5; // Error, can't assign length
-
有一個
storage
事件,它會在我們修改資料時觸發。這個事件不會發生在類似物件的存取中。我們將在本章稍後看到這一點。
迴圈遍歷 key
如我們所見,這些函式提供「透過 key 取得/設定/移除」功能。但是如何取得所有已儲存的值或 key?
不幸的是,儲存物件不可迭代。
一種方法是像陣列一樣迴圈遍歷它們
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
– 發生更新的文件網址。storageArea
– 發生更新的localStorage
或sessionStorage
物件。
重點是:事件觸發在所有可以存取儲存空間的 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
- 更新資料的文件網址。
此外,event.storageArea
包含儲存空間物件 - 這個事件對 sessionStorage
和 localStorage
都是相同的,因此 event.storageArea
參照被修改的那個。我們甚至可能想要在其中設定一些東西,來「回應」變更。
這允許來自同一個來源的不同視窗交換訊息。
現代瀏覽器也支援 廣播頻道 API,這是用於同來源視窗間通訊的特殊 API,它的功能更齊全,但支援度較低。有一些函式庫可以根據 localStorage
來填補這個 API,讓它可以在任何地方使用。
摘要
網頁儲存空間物件 localStorage
和 sessionStorage
允許在瀏覽器中儲存金鑰/值對。
key
和value
都必須是字串。- 限制為 5mb+,視瀏覽器而定。
- 它們不會過期。
- 資料與來源(網域/埠/通訊協定)綁定。
localStorage |
sessionStorage |
---|---|
在所有具有相同來源的分頁和視窗之間共用 | 在瀏覽器分頁中可見,包括來自相同來源的 iframe |
瀏覽器重新啟動後仍存在 | 頁面重新整理後仍存在(但分頁關閉後則不會) |
API
setItem(key, value)
– 儲存 key/value 成對資料。getItem(key)
– 透過 key 取得 value。removeItem(key)
– 移除 key 及其 value。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…)