localStorage の基本 — localStorage.setItem('k', v) / localStorage.getItem('k')
localStorage は「ブラウザに文字列として永続保存(タブや再起動後も保持)」できる仕組みです。キーと値で扱い、値は必ず文字列になります。
まずは基礎
<script>
// 書き込み(保存)
localStorage.setItem("greeting", "こんにちは");
// 読み出し(取得)
const val = localStorage.getItem("greeting"); // "こんにちは"
// ないキーは null
console.log(localStorage.getItem("nope")); // null
// 削除・全消去
localStorage.removeItem("greeting");
localStorage.clear();
</script>
HTML- 保存範囲: 同一オリジン(ドメイン・プロトコル・ポート)内で共有。
- 型: 値は文字列。オブジェクト/配列は JSON 化が必要。
オブジェクトや配列を保存するテンプレート
// 保存(JSON化)
const user = { name: "Aki", age: 20 };
localStorage.setItem("user", JSON.stringify(user));
// 取得(JSONを復元)
const raw = localStorage.getItem("user");
const data = raw ? JSON.parse(raw) : null;
console.log(data?.name); // "Aki"
JavaScript- ポイント:
getItemがnullのときにJSON.parse(null)はエラーになるため、nullチェックを挟む。
よく使うテンプレート集
設定の保存と復元(ダークモード例)
// 保存
function saveTheme(isDark) {
localStorage.setItem("theme", isDark ? "dark" : "light");
}
// 復元
function loadTheme() {
const theme = localStorage.getItem("theme") || "light";
document.documentElement.dataset.theme = theme; // data-theme="dark|light"
}
loadTheme();
JavaScript入力内容の一時保存(フォーム復元)
const input = document.getElementById("memo");
input.addEventListener("input", () => {
localStorage.setItem("memo:text", input.value);
});
window.addEventListener("DOMContentLoaded", () => {
input.value = localStorage.getItem("memo:text") || "";
});
JavaScriptTODO を配列で保持(追加・削除)
const KEY = "todos";
function loadTodos() {
const raw = localStorage.getItem(KEY);
return raw ? JSON.parse(raw) : [];
}
function saveTodos(todos) {
localStorage.setItem(KEY, JSON.stringify(todos));
}
function addTodo(text) {
const todos = loadTodos();
todos.push({ id: crypto.randomUUID(), text });
saveTodos(todos);
}
JavaScript実務でのコツ
- 名前空間で整理: 関連キーに接頭辞を付ける(例:
app:theme,app:user)と衝突や混乱を防げる。 - try/catch で安全に: JSON の破損や保存容量超過に備えて、復元時は
try/catch。
function safeParse(raw, fallback = null) {
try { return raw ? JSON.parse(raw) : fallback; }
catch { return fallback; }
}
JavaScript- 容量の目安: 数MB程度。大量データは不向き。必要ならサーバーや IndexedDB を検討。
- 同期 API:
setItem/getItemは同期で即時に動く。高頻度で大きなデータを書き込まない。 - storage イベント: 他タブでの変更を受け取れる。
window.addEventListener("storage", (e) => {
if (e.key === "theme") console.log("テーマが他タブで更新:", e.newValue);
});
JavaScript- セキュリティ: 機密情報(トークン、個人情報)は保存しない。XSS があると読み取られる可能性があるため危険。
ありがちなハマりポイントと対策
- nullをそのままパースしてエラー:
- 対策:
const raw = getItem(...); raw ? JSON.parse(raw) : ...の形にする。
- 対策:
- 文字列として保存される誤解:
- 対策: 数値も
"123"になる。必要なら取得後にNumber(...)等で変換。
- 対策: 数値も
- 容量超過(QuotaExceededError):
- 対策: データを小さく保つ。不要キーの削除、画像や巨大テキストは保存しない。
- 別環境で値が見つからない:
- 対策: オリジンが違うと共有されない。サブドメインやプロトコル差異に注意。
練習問題(設定保存のミニアプリ)
<label><input type="checkbox" id="dark"> ダークモード</label>
<select id="lang">
<option value="ja">日本語</option>
<option value="en">English</option>
</select>
<script>
const DARK_KEY = "app:dark";
const LANG_KEY = "app:lang";
// 復元
document.getElementById("dark").checked =
localStorage.getItem(DARK_KEY) === "1";
document.getElementById("lang").value =
localStorage.getItem(LANG_KEY) || "ja";
// 変更を保存
document.getElementById("dark").addEventListener("change", (e) => {
localStorage.setItem(DARK_KEY, e.target.checked ? "1" : "0");
document.documentElement.classList.toggle("dark", e.target.checked);
});
document.getElementById("lang").addEventListener("change", (e) => {
localStorage.setItem(LANG_KEY, e.target.value);
// 言語切り替えの反映はここに
});
// 他タブからの変更を反映
window.addEventListener("storage", (e) => {
if (e.key === DARK_KEY) {
const on = e.newValue === "1";
document.getElementById("dark").checked = on;
document.documentElement.classList.toggle("dark", on);
}
if (e.key === LANG_KEY) {
document.getElementById("lang").value = e.newValue || "ja";
}
});
</script>
HTML直感的な指針
- 「文字列で永続保存」→ JSON で包んで取り出すときに安全復元。
- キーは整理して、小さく・安全に。機密は保存しない。
- 他タブと連携したいなら storage イベントで即時反映。
