跳至主要内容

Day 16: 原理篇 —— 瀏覽器小帳本:幫使用者存下他的個人設定(LocalStorage)

在單純由記憶體驅動的前端程式中,每當使用者重新整理網頁,原本設定的深色模式、填寫中的表單或購物車清單都會瞬間煙消雲散。本章節將帶領冒險者解鎖瀏覽器的「永久存檔點」—— LocalStorage。我們將剖析 Web Storage 的底層儲存機制,橫向對比 LocalStorage、SessionStorage 與 Cookie 在保存期限與容量上的本質差異,並掌握 setItemgetItem 等基礎增刪改查指令。同時,我們將深入探討如何運用 JSON.stringify()JSON.parse() 實現複雜物件的打包與拆箱序列化,並建立職人必備的 XSS 防禦與資料容錯防呆思維。

本文同步分享於2026鐵人賽:JS 核心重構:勇者轉職傳說

📜 這裡的修煉規則

孩子,在踏上今日的領地前,先坐下來喝杯酒吧。 修煉的路很長,別急著奔跑,先聽聽這份卷軸裡的古老叮嚀。

我在每一站的盡頭都為你鋪設了 實戰演武場 CodePen。那不只是程式碼的拼湊,而是你在這場暴風雨中,試圖用邏輯點燃的一顆星火。 成功突圍後,別忘了帶著你的戰利品回到 QuestBoard 佈告欄。在那裡,你會發現自己從不孤單,公會的夥伴們都正舉杯等待你的歸來。

記住...

導師看重的從來不是你的劍法有多華麗,而是當你被邏輯擊潰、滿身泥濘後,依然選擇握緊理性的劍柄,再次向真相發起衝鋒的勇氣。

🛡️ 【公會大廳:導師的修煉導讀】

「導師,為什麼我辛苦幫梅大叔設定好的『黑夜模式』介面,只要他一重新整理網頁,整個公會大廳就又變回白茫茫一片,差點閃瞎他的眼啊!」

我拍掉手上的公文塵埃,指著櫃檯後面的一個皮革小帳本說:「冒險者,那是因為你的程式碼只存在於當前的『執行泡泡(記憶體)』中。一旦泡泡破了(頁面重整),一切都會歸零。

今天,我要教你如何動用瀏覽器的 『自動存檔點 (Save Point)』。我們會把使用者的心聲,一字一句刻在瀏覽器的皮革帳本上。即便勇者關掉電腦去睡覺,明天醒來,他的偏好依然會在。這就是 LocalStorage 的持久化魔法。」


💡 【導師講義:底層真相探究】

1. 儲存三兄弟大 PK

在瀏覽器的世界,我們有三種方式可以存檔,但它們的「保存期限」與「職責範圍」完全不同:

特性LocalStorageSessionStorageCookie
保存期限永久存檔 (手動清才消失)關閉當前分頁即消失依設定的過期時間消失
容量大小5MB (容量最大)5MB極小(約 4KB
傳輸行為僅留在本機,不隨請求發送僅留在本機,不隨請求發送每次 HTTP 請求自動攜帶
主要用途個人喜好設定、待辦清單、快取資料暫存表單輸入、單次流程狀態身分認證 Token、廣告追蹤
🏹 導師的辨析:儲存三兄弟的戰略定位

在現代前端開發中,除非你要處理跟後端伺服器通訊的驗證憑據(Cookie),否則 90% 的本機客戶端存檔需求,我們都優先指派 LocalStorage 出動!


2. 存檔指令:增、刪、改、查

LocalStorage 的操作非常直觀,就像在用一把四段式機關鑰匙:

storage-crud.js
// 1. 存入 (setItem):傳入 Key(鍵)與 Value(值)
localStorage.setItem("heroName", "辛爾梅");

// 2. 讀取 (getItem):直接拿鑰匙去取回數值
const myHero = localStorage.getItem("heroName"); // "辛爾梅"

// 3. 刪除 (removeItem):指定特定標籤單項排除
localStorage.removeItem("heroName");

// 4. 清空 (clear):整個帳本全部重設燒毀
localStorage.clear();

3. 資料打包魔法:JSON 序列化

這是新手最容易踩到的致命陷阱:LocalStorage 只能儲存「字串」!如果你直接把一個物件或陣列存進去,瀏覽器會自動調用 .toString() 將其轉化為無效的 [object Object]

為了解決這個問題,我們需要職人的「打包拆箱術」:

  • JSON.stringify() (打包):將 JavaScript 物件/陣列幻化為 JSON 字串,才能安全塞入儲存槽。
  • JSON.parse() (拆箱):將 JSON 字串召喚回原生物件/陣列,才能重新使用物件屬性點符號(.)或陣列方法操作。
json-serialization.js
const heroData = { name: "辛爾梅", level: 99 };

// ❌ 錯誤做法:直接存物件,會被強制轉成無效字串
localStorage.setItem("save", heroData); // 裡面會變成 "[object Object]"

// ✅ 正確做法:先打包成 JSON 字串再存入
localStorage.setItem("save", JSON.stringify(heroData));

// 從帳本取出時,記得拆箱還原為物件
const getSave = JSON.parse(localStorage.getItem("save"));
console.log(getSave.name); // "辛爾梅"

4. 邏輯流向圖解

🛖 營火叮嚀:導師的圖解心法

想像 LocalStorage 是一個巨大的壁掛櫃,每個櫃子都有一個專屬標籤(Key)。你存進去的是文字(Value),拿出來的也是文字。打包拆箱魔法就像是把立體的勇者裝備折疊收納成扁平捲軸,放入櫃中;需要使用時,再展開還原成生動的實體。

存檔邏輯圖


⚔️ 【戰術對抗:學長與學弟的代碼對決】

招式示範:持久化黑夜模式 (Dark Mode)

❌ 冒險學弟:只管當下,不管未來

  • 負能量評級:🔴 重整即歸位 / 🔴 被使用者投訴閃瞎眼
bad-practice.js
const btn = document.querySelector("#theme-toggle");

btn.addEventListener("click", () => {
document.body.classList.toggle("dark-mode");
// 致命傷:沒有持久化存檔,使用者重新整理網頁後又回到預設白色
});

✅ 勇者學長:帳本紀錄,重啟無憂

  • 利潤評級:🟢 體驗極佳 / 🟢 專業級雙向狀態同步
good-practice.js
const btn = document.querySelector("#theme-toggle");

// 1. 初始化:頁面載入時先翻閱帳本恢復狀態
const currentTheme = localStorage.getItem("theme");
if (currentTheme === "dark") {
document.body.classList.add("dark-mode");
}

// 2. 切換時:介面變更與帳本寫入雙向同步
btn.addEventListener("click", () => {
const isDark = document.body.classList.toggle("dark-mode");
localStorage.setItem("theme", isDark ? "dark" : "light");
});
💡 導師講評:雙向同步的標配思維

學長寫法的關鍵在於 「雙向同步」:操作介面時同步寫入帳本,頁面載入時優先讀取帳本並應用。這正是構建專業級 Web 應用的標準架構思維。


🏰 【勇者精英課:邁向職人的進階架構】

為什麼我們絕對不把敏感資料放 LocalStorage?

⚠️ 實戰雷區:避開那些致命陷阱

雖然 LocalStorage 非常便利,但它存在一項重大的資安特性:在同一網域下的任何 JavaScript 腳本都能直接讀取它(容易遭受 XSS 跨站腳本攻擊)。

因此,專業職人的第一鐵律:絕對不要在 LocalStorage 儲存密碼、信用卡號或未受保護的高敏感 Token。帳本是用來記錄「使用者偏好設定」的,絕不是用來當「金庫密碼箱」。

此外,LocalStorage 的 5MB 容量上限雖然日常夠用,但若嘗試將大量高解析度圖片轉成 Base64 字串硬塞進去,將會迅速耗盡配額並拋出 QuotaExceededError 異常。優雅的工程師必須懂得權衡與節制。


🛖 營火叮嚀:導師的經驗談

孩子,導師當年第一次寫 JSON.parse 時,因為沒考慮到「如果帳本裡根本沒這筆資料」的情況,導致程式直接拋錯崩潰。

記住,當 localStorage.getItem("key") 找不到對應的標籤時,它會回傳 null。如果你直接對 null 做屬性存取(例如 JSON.parse(null).name),程式就會當場炸裂。

養成習慣:在操作取回的資料前,善用可選串連(?.)或條件判斷預先驗證資料是否存在,並提供合理的預設回退值。

天色微亮,營火雖已燃盡,但你眼中卻閃爍著領悟的光芒。在前往演武場挑戰關卡前,我已經幫你把靈魂碎片精煉成了這份「戰術錦囊」。拿好它,今日的任務不再是負擔,而是你證明自我的舞台。去吧,公會的英雄榜在等著你的戰報。

📝 【夥伴筆記:今日修煉精華】

這份筆記是你的隨身護身符,卡關時看一眼,真相就在裡面。

  • setItem / getItem:鍵值對(Key-Value)存取核心指令。
  • JSON.stringify():將物件與陣列魔法打包為字串的唯一通道。
  • JSON.parse():將字串存檔拆箱還原為可操作的物件結構。
  • 資安防禦第一:LocalStorage 不具備加密隔離性,嚴禁存放機密憑據。
  • null 防呆處理:讀取不存在的鍵值會回傳 null,取值前務必先做安全檢查。

🎯 【實戰演武場】

⚔️ 任務鑑定條件:

  1. 完成 📜 本日實戰任務 (CodePen)
  2. 將 CodePen 網址貼至 QuestBoard,並回填鑑定報告:
    • 初心者:存檔術啟動 (成就感發掘)
        1. 你是否成功打開 DevTools > Application 找到你的帳本並親手修改了數值?發現它也會同步改變網頁畫面的驚喜了嗎?
    • 冒險者:打包拆箱的真相 (理性挑戰)[⚡ 觀念辨析]
        1. 如果我們不用 JSON.stringify 直接把一個陣列存入 LocalStorage,拿出來時它會變什麼樣子?還能用 forEach 嗎?
  3. 任務完成後,你的名字將永遠標記在公會的英雄榜上!

📚 【圖書館卷軸與前後站連結】