JavaScript:ブラウザにデータを保存(localStorage)

投稿日:2026-01-13

音声

※ AI音声で読み上げます

目次

  1. localStorage/sessionStorageの違い
  2. 保存・読み込み・削除の基本
  3. JSONで保存する定石
  4. 保存データのバージョン管理(簡易)
  5. 壊れたデータへの復旧(try/catch)
  6. 注意(ここだけ)
  7. 要約

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.stringifyJSON.parse が前提です。

  • 保存データは壊れたり古い形式のまま残ることがあります。読み込みは try/catch と「初期値フォールバック」を用意します。

  • 容量は無限ではありません。大きいデータ(画像や大量ログ)を入れる用途には向きません。

要約

  1. localStorage は永続的に保存され、sessionStorage はタブ単位の一時保存になりますので、用途に応じて使い分ける必要があります。

  2. 基本操作は setItem/getItem/removeItem で行い、保存できる値は文字列として扱われます。

  3. オブジェクトは JSON.stringify/JSON.parse を使って保存・復元し、Date などは ISO 文字列に変換してから復元する必要があります。

  4. {v, payload} の形でバージョン管理を行い、読み込み時にマイグレーションを実施するのが有効です。

  5. JSON.parse は try/catch で保護し、壊れたデータは削除して再初期化するのが要チェックです。