JavaScript Web Storage (localStorage / sessionStorage)
Web Storage API 提供了在瀏覽器中儲存資料的機制,比 Cookie 更簡單易用,儲存容量也更大(通常 5-10 MB)。
localStorage 與 sessionStorage
Web Storage 分為兩種:
| 特性 | localStorage | sessionStorage |
|---|---|---|
| 資料生命週期 | 永久保存,除非手動清除 | 分頁關閉時清除 |
| 作用範圍 | 同源的所有分頁共享 | 僅限當前分頁 |
| 儲存容量 | 約 5-10 MB | 約 5-10 MB |
兩者的 API 用法完全相同,只是資料的生命週期不同。
基本操作
儲存資料 - setItem()
// 儲存字串
localStorage.setItem('username', 'Mike');
sessionStorage.setItem('token', 'abc123');
// 也可以用屬性方式存取
localStorage.username = 'Mike';
localStorage['username'] = 'Mike';
讀取資料 - getItem()
var username = localStorage.getItem('username');
console.log(username); // 'Mike'
// 如果 key 不存在,回傳 null
var notExist = localStorage.getItem('notExist');
console.log(notExist); // null
// 屬性方式存取
var username = localStorage.username;
刪除資料 - removeItem()
localStorage.removeItem('username');
清除所有資料 - clear()
localStorage.clear();
sessionStorage.clear();
取得資料數量 - length
console.log(localStorage.length);
取得第 n 個 key - key()
// 取得第一個 key
var firstKey = localStorage.key(0);
儲存物件和陣列
Web Storage 只能儲存字串。如果要儲存物件或陣列,需要先轉換成 JSON 字串:
// 儲存物件
var user = {
name: 'Mike',
age: 30,
email: 'mike@example.com'
};
localStorage.setItem('user', JSON.stringify(user));
// 讀取物件
var userStr = localStorage.getItem('user');
var user = JSON.parse(userStr);
console.log(user.name); // 'Mike'
// 儲存陣列
var fruits = ['Apple', 'Banana', 'Orange'];
localStorage.setItem('fruits', JSON.stringify(fruits));
// 讀取陣列
var fruits = JSON.parse(localStorage.getItem('fruits'));
console.log(fruits[0]); // 'Apple'
讀取不存在的 key 會得到
null,而 JSON.parse(null) 會回傳 null,所以記得做檢查。遍歷所有資料
// 方法一:使用 for 迴圈
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
var value = localStorage.getItem(key);
console.log(key + ': ' + value);
}
// 方法二:使用 Object.keys()
Object.keys(localStorage).forEach(function(key) {
console.log(key + ': ' + localStorage.getItem(key));
});
storage 事件
當 localStorage 的資料在其他分頁被修改時,會觸發 storage 事件。這可以用來在多個分頁之間同步資料:
window.addEventListener('storage', function(event) {
console.log('Key: ' + event.key);
console.log('舊值: ' + event.oldValue);
console.log('新值: ' + event.newValue);
console.log('來源: ' + event.url);
});
storage 事件只會在其他同源分頁觸發,不會在當前分頁觸發。
實用範例
記住使用者偏好設定
// 儲存使用者設定
function saveSettings(settings) {
localStorage.setItem('userSettings', JSON.stringify(settings));
}
// 載入使用者設定
function loadSettings() {
var settings = localStorage.getItem('userSettings');
return settings ? JSON.parse(settings) : {
theme: 'light',
language: 'zh-TW',
fontSize: 16
};
}
// 使用
var settings = loadSettings();
console.log(settings.theme);
settings.theme = 'dark';
saveSettings(settings);
簡易購物車
var cart = {
items: [],
load: function() {
var data = localStorage.getItem('cart');
this.items = data ? JSON.parse(data) : [];
},
save: function() {
localStorage.setItem('cart', JSON.stringify(this.items));
},
add: function(product) {
this.items.push(product);
this.save();
},
remove: function(index) {
this.items.splice(index, 1);
this.save();
},
clear: function() {
this.items = [];
localStorage.removeItem('cart');
}
};
// 使用
cart.load();
cart.add({ id: 1, name: 'iPhone', price: 30000 });
cart.add({ id: 2, name: 'MacBook', price: 50000 });
console.log(cart.items);
表單自動儲存
var form = document.getElementById('myForm');
var formKey = 'formDraft';
// 載入暫存的表單資料
function loadDraft() {
var draft = localStorage.getItem(formKey);
if (draft) {
var data = JSON.parse(draft);
form.title.value = data.title || '';
form.content.value = data.content || '';
}
}
// 自動儲存表單
function saveDraft() {
var data = {
title: form.title.value,
content: form.content.value
};
localStorage.setItem(formKey, JSON.stringify(data));
}
// 輸入時自動儲存
form.addEventListener('input', saveDraft);
// 送出後清除暫存
form.addEventListener('submit', function() {
localStorage.removeItem(formKey);
});
// 頁面載入時還原
loadDraft();
檢查瀏覽器支援
function storageAvailable(type) {
try {
var storage = window[type];
var test = '__storage_test__';
storage.setItem(test, test);
storage.removeItem(test);
return true;
} catch (e) {
return false;
}
}
if (storageAvailable('localStorage')) {
// localStorage 可用
} else {
// localStorage 不可用,可能是隱私模式
}
在某些瀏覽器的隱私/無痕模式下,Web Storage 可能無法使用或有限制。
Web Storage vs Cookie
| 特性 | Web Storage | Cookie |
|---|---|---|
| 容量 | 5-10 MB | 約 4 KB |
| 自動傳送 | 不會傳送到伺服器 | 每次請求都會傳送 |
| API | 簡單直覺 | 較繁瑣 |
| 過期機制 | 無(localStorage)/ 分頁關閉(sessionStorage) | 可設定過期時間 |
選擇建議:
- 使用 Web Storage:純前端資料儲存,如使用者偏好、快取資料
- 使用 Cookie:需要傳送到伺服器的資料,如身份驗證 token
安全性注意事項
- 不要儲存敏感資料:Web Storage 的資料可以被 JavaScript 讀取,容易受到 XSS 攻擊
- 同源政策:資料只能被同源的頁面存取,但同源的所有頁面都能存取
- 驗證資料:從 Storage 讀取的資料應該驗證後再使用
// 讀取資料時加上驗證
function getUser() {
try {
var data = localStorage.getItem('user');
if (!data) return null;
var user = JSON.parse(data);
// 驗證資料格式
if (user && typeof user.name === 'string') {
return user;
}
return null;
} catch (e) {
return null;
}
}