一篇文章圖文並茂地帶你輕鬆學會 HTML5 storage
阿新 • • 發佈:2021-02-13
## html5 storage api
`localStorage` 和 `sessionStorage` 是 `html5` 新增的用來儲存資料的物件,他們讓我們可以以鍵值對的形式儲存資訊。
### 為什麼要有 `storage` ?
我們已經有了 `session` 可以幫助我們儲存資訊,為何還需要 `storage` 呢?
1. 各個瀏覽器的 `cookie` 長度大概只能在 `4kb` 左右,而 `storage` 大概能達到 `5M`,這意味著可以儲存更多的資訊
2. `cookie` 可以被後端更改,在每次進行網路請求的時候都會被髮送給伺服器,而 `storage` 不會,這意味著這個儲存是完全受控於前端(JavaScript)的。
### storage 型別
`storage` 一共有兩種
1. `localStorage`
這個儲存物件的儲存和 `origin` 有關,即只要是同域名同協議同埠,儲存是共享的。儘管關機了,或是關掉瀏覽器了,只要開啟同源網站,儲存的資料會依然存在,資料不會過期消失。
2. `sessionStorage`
這個儲存物件的儲存是暫時的,只保持在當前會話中,簡單來說就是和瀏覽器的一個 `tab` 有關,只要 `tab` 關掉了再開啟資料就沒了,但是在當前介面重新整理的話,資料就還在(這個時候認為是一個 `tab`)。
兩個 `storage` 的 `api` 很相似,下面以 `localStorage` 為例
### localStorage 演示
#### 基礎 `api`
```js
localStorage.setItem("name", "huro"); // 設定鍵值對
```
![](https://img2020.cnblogs.com/blog/2286610/202102/2286610-20210213185656582-617272945.png)
可以在 `chrome` 瀏覽器的控制檯進行觀察,這裡已經設定上去了。下面也可以做相應的測試。
```js
localStorage.getItem("name"); // huro
localStorage.removeItem("name"); // 刪除某個鍵
localStorage.clear(); // 刪除所有鍵值對
localStorage.key(0); // 獲得索引為 0 的key
localStorage.length; // 獲得 `localStroage` 的鍵的個數
```
以上是 `storage` 的 `api`
唯一需要注意的是 `key(index)` 這個 `api` 和 `key` 被設定的先後是沒有關係的。
#### 類物件操作
也可以用類物件的方法操作
```js
localStorage.name = "huro";
console.log(localStorage.name); // huro
delete localStorage.name; // 刪除鍵
```
但是上面的做法不推薦,如果用的是某些特殊的 `key` 例如 `length` 就會報錯,因為原先 `localStorage.length` 表示獲得鍵值對長度,理應是不能修改的。
```js
localStorage["length"] = 4; // 修改無效
```
因此不推薦用這個做法修改 `storage`
#### 遍歷鍵值
由於 `storage` 並沒有 `Symbol.iterator` 屬性,這意味著 `storage` 不能用 `for of`迴圈遍歷。以下有三種遍歷方式。
假設我們只有一個鍵值對 `name: huro`
1. `for in` 迴圈
```js
for (let key in localStorage) {
console.log(key);
}
```
![](https://img2020.cnblogs.com/blog/2286610/202102/2286610-20210213185643701-1211698067.png)
上述的寫法是錯誤的,因為 `for in` 迴圈會遍歷原型鏈上的屬性和方法,因此需要稍作改善。
```js
for (let key in localStorage) {
if (!localStorage.hasOwnProperty(key)) {
continue;
}
console.log(key);
}
```
這個時候就能正確的只打印出鍵 `name`
2. 簡單 `for` 迴圈
```js
for(let i = 0; i < localStorage.length; i+= 1) {
let key = localStorage.key(i);
console.log(key);
}
```
這個時候能正確的只打印出鍵 `name`
3. `Object.keys()`
這個方法會獲得某個物件自身的 `key`,而不會管原型鏈上的
```js
const keys = Object.keys(localStorage);
for(let key of keys) {
alert(key);
}
```
而且獲得的 `key` 是陣列,具有 `iterator` 因此可以用 `for of` 遍歷
這個時候能正確的只打印出鍵 `name`
#### 只能是 `string`
`storage` 被設計出來比較不足的地方是,鍵和值都只能是 `string` 型別的,如果不是的話,會自動轉換成 `string`。
由於是隱式轉換,初學者往往不知道,這意味著可能帶來一些 `bug`
```js
localStorage.user = { name: "huro" };
console.log(localStorage.user); // [object Object]
```
上述程式碼在儲存 `user` 的時候,被自動呼叫 `toString` 方法,轉化為了 `[object Object]`
#### `storage` 事件
`storage` 事件返回一個物件,裡面包含幾個引數
1. `key` 改變的鍵
2. `oldValue` => `舊值 || null`
3. `newValue` => `新值 || null`
4. `url` 觸發這個事件的 `url` 地址
5. `storageArea` 要麼是 `localStorage` 要麼是 `sessionStorage` 取決與是更改哪個`storage`的
```js
// 1.html
window.addEventListener("storage", (state) => {
console.log(state.key, state.value, state.url); // name huro ./2.html(實際 url 是絕對路徑)
})
// 2.html
localStorage.setItem("name", "huro");
```
還記得我們之前說過, `localStorage` 只要是同源都可以分享嗎,這意味如果我們打開了兩個視窗,只要他們是同源的,我們可以用上述的監聽事件,監聽另一個埠修改 `storage`,也就是可以實現不同的視窗之間的資料共享。
注意: 經測試,`chrome` `edge` 等現代瀏覽器不會觸發自身檔案或同文件的 `storage` 事件,即必須是兩個不同的 `html` 才會互相觸發。
例如 `test1.html` 和 `test2.html` 都設定了 `storage` 監聽事件,且同源。
則 `test1.html` 的 `storage` 的 `api` 事件會觸發 `test2.html` 的,但是不能觸發本身的 `storage` 監聽事件。
另外這裡的 `api` 事件也有限制,經過筆者測試,似乎只有
1. `setItem`
2. `getItem`
3. `removeItem`
有效果,而 `clear` 事件是沒有效果的。
上面全程用 `localStorage` 演示,
`sessionStorage` 也是類似的,讀者有興趣可以自行碼一下程式碼。
### 總結
`storage` 是很好的一個 `html5` 特性,讓我們方便快捷的儲存資料,美中不足的是隻能儲存字元型資料,不過也很容易解決這個問題。同時利用監聽事件,也可以實現不同視窗之間的廣播機制。是非常實用的一個