JavaScript:ブラウザにデータを保存(localStorage)
音声
目次
localStorage/sessionStorageの違い
localStorageは「ブラウザ内に小さなデータを保存できる、手軽な保存場所」です(同一オリジン=同じドメイン/プロトコル/ポートの範囲で共有されます)。
localStorageは window にぶら下がっているため、ページ内のJavaScriptから localStorage と直接書けば呼び出せます(= window.localStorage の省略形)。
基本的に「消すまで残る」永続領域です(ブラウザを閉じても残ります)。ただしユーザー操作やブラウザ設定(サイトデータ削除/ストレージ削除)で消えることはあります。
一方、sessionStorageは「タブ/ウィンドウ単位の一時置き場」です。同一オリジンでも別タブとは共有されず、タブを閉じると消えます。
どちらも文字列として保存されるため、機密情報(平文トークンなど)の保存は避けたい例です。使い分けは「永続で良いか」「そのタブを開いている間だけ使えれば良いか」で決めるとよいです。
保存・読み込み・削除の基本
APIはシンプルで、setItem/getItem/removeItem(必要なら clear)を使います。値は文字列として保存される点を押さえる必要があります。
localStorage.setItem('demo.key', 'hello'); // 保存(文字列)
const v = localStorage.getItem('demo.key'); // 読み込み(無ければ null)
localStorage.removeItem('demo.key'); // 削除
UIでのテスト(ボタン操作など)を併用すると挙動把握が早いです。
JSONで保存する定石
オブジェクトや配列は JSON.stringify で保存し、JSON.parse で復元します。Date などの特殊型は ISO 文字列にして保存し、読み込み時に new Date(...) で復元します。
要チェックとして、stringify を忘れると "[object Object]" など意図しない文字列が保存されます。
const KEY = 'profile';
const data = { name: 'Taro', updatedAt: new Date().toISOString() };
// 保存:オブジェクトは stringify が必須
localStorage.setItem(KEY, JSON.stringify(data));
// 読み込み:無い場合に備えて 'null' にフォールバック
const loaded = JSON.parse(localStorage.getItem(KEY) || 'null');
// Dateは ISO 文字列 → new Date(...) で復元
const updatedAt = loaded ? new Date(loaded.updatedAt) : null;
保存データのバージョン管理(簡易)
将来的なフォーマット変更に備え、保存物にバージョンを持たせます。{ v, payload } 形式にすると読み込み時のマイグレーションが扱いやすいです。
const KEY = 'app.data';
const VERSION = 2;
function save(payload) {
// 保存形式:{ v, payload } に固定
localStorage.setItem(KEY, JSON.stringify({ v: VERSION, payload }));
}
function migrateIfNeeded(saved) {
// 例:v1 → v2 に変換(必要なときだけ)
if (saved.v === 1) {
return { v: 2, payload: { ...saved.payload, migrated: true } };
}
return saved;
}
読み込み時は v を見て必要な変換を行い、互換性を保ちます。
壊れたデータへの復旧(try/catch)
外部編集や拡張機能で値が壊れていることがあるため、JSON.parse は必ず try/catch で保護し、失敗したら該当キーを削除してデフォルトを返すのが安全です。
最小の UI とスクリプト(CodePen 等で動作確認可)です。
HTML(例)
<button id="saveBtn">保存</button>
<button id="loadBtn">読み込み</button>
<button id="delBtn">削除</button>
<pre id="out">ここに結果が出ます</pre>
JS(要点)
// どのボタン操作が、どのAPI(保存/読込/削除)に対応するかが要点
const KEY = 'app.data';
const VERSION = 2;
const out = document.getElementById('out');
const show = (msg, obj) => {
out.textContent = msg + (obj ? "\n" + JSON.stringify(obj, null, 2) : "");
};
function migrateIfNeeded(saved) {
// 例:v1 → v2(必要になったらここで変換)
if (saved && saved.v === 1) {
return { v: 2, payload: { ...saved.payload, migrated: true } };
}
return saved;
}
function saveData(obj) {
// 保存:setItem(文字列しか入らないので stringify)
localStorage.setItem(KEY, JSON.stringify({ v: VERSION, payload: obj }));
console.log('saved');
show('保存しました', obj);
}
function loadData() {
// 読み込み:getItem → parse(壊れている可能性があるので try/catch)
const raw = localStorage.getItem(KEY);
if (!raw) { show('未保存です(キーがありません)'); return null; }
try {
const parsed = migrateIfNeeded(JSON.parse(raw));
const payload = parsed?.payload ?? null;
console.log('loaded', payload);
show('読み込みました', payload);
return payload;
} catch (e) {
console.error('復旧: 壊れたデータを削除します', e);
localStorage.removeItem(KEY);
show('壊れていたので削除して初期化しました');
return null;
}
}
function deleteData() {
// 削除:removeItem
localStorage.removeItem(KEY);
console.log('deleted');
show('削除しました');
}
// UI(ボタン)→ 処理(保存/読込/削除)をつなぐ:ここが“文章とコードの接点”
document.getElementById('saveBtn').addEventListener('click', () => {
saveData({ name: 'Taro', updatedAt: new Date().toISOString() });
});
document.getElementById('loadBtn').addEventListener('click', loadData);
document.getElementById('delBtn').addEventListener('click', deleteData);
保存→読み込み→削除の流れが正しく動くかを UI で確認します。
最小コード: このあとに示す短いJavaScriptコードを使います。
貼り付け場所: CodePenならHTML欄にボタンと出力用pre、JS欄にJavaScriptを貼ります(同じブロックに混在させません)。HTMLファイルなら<body>の最後(</body>直前)に<script>を置くか、DOMContentLoaded内で実行します。
実行方法: ブラウザで開くか、CodePenのRunで実行します。Consoleで結果を見ます。
確認方法: 1) 保存を押して画面にJSONが出る 2) 読み込みで同じ内容が出る 3) 削除後に読み込みすると「未保存」が出る、で確認します。
よくあるミス: Consoleを開いていないため出力が見えない、または id のスペル違い(saveBtn など)で null になり addEventListener で落ちることがあります。
使い分けの基準: 永続なら localStorage、タブを閉じたら消えてよいなら sessionStorage。保存形式は {v, payload} にして将来の変更に備え、読み込みは try/catch + 失敗時削除で安全側に倒します。
注意(ここだけ)
localStorageは「文字列しか保存できない」ので、オブジェクトは
JSON.stringify→JSON.parseが前提です。保存データは壊れたり古い形式のまま残ることがあります。読み込みは
try/catchと「初期値フォールバック」を用意します。容量は無限ではありません。大きいデータ(画像や大量ログ)を入れる用途には向きません。
要約
localStorage は永続的に保存され、sessionStorage はタブ単位の一時保存になりますので、用途に応じて使い分ける必要があります。
基本操作は setItem/getItem/removeItem で行い、保存できる値は文字列として扱われます。
オブジェクトは JSON.stringify/JSON.parse を使って保存・復元し、Date などは ISO 文字列に変換してから復元する必要があります。
{v, payload} の形でバージョン管理を行い、読み込み時にマイグレーションを実施するのが有効です。
JSON.parse は try/catch で保護し、壊れたデータは削除して再初期化するのが要チェックです。