1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【JavaScript】localStorage を完全に理解する:基本から実務で使える管理テクニックまで

1
Posted at

TL;DR (忙しい人のための3行まとめ)

  • ブラウザにデータを永続化 できる Key-Value 型のストレージ(容量は一般的に 5MB 程度)。
  • 保存できるのは 文字列のみ なので、オブジェクトを扱う際は JSON.stringify / JSON.parse が必須。
  • 同期処理 であるため、大量データの読み書きはメインスレッドをブロックする点に注意が必要。

Introduction

「ユーザーが選んだダークモード設定を、リロード後も保持したい」
「入力途中のフォーム内容を、誤ってタブを閉じた時のために一時保存したい」

フロントエンド開発をしていると、こういった 「サーバーに送るほどではないが、ブラウザにちょっとしたデータを残したい」 というシーンに頻繁に遭遇しますよね?

そんな時に真っ先に候補に上がるのが、Web Storage API の一つである localStorage です。 Cookie よりも扱いやすく、容量も大きいこの機能を「なんとなく」使っていませんか?

本記事では、localStorage の基本操作はもちろん、実務でハマりやすい「オブジェクトの保存」や「セキュリティの懸念点」まで、コードベースで解説します。これを読めば、適切なシーンで迷いなく localStorage を選定できるようになるでしょう。

Prerequisites (前提環境)

本記事のコードは以下の環境を想定しています。

  • モダンブラウザ ( Chrome, Firefox, Edge, Safari ) の最新版
  • ES6+ ( const / let , アロー関数等 ) が動作する JavaScript 環境

1. localStorage とは? (基本概念)

localStorage は、ブラウザ内にデータを保存する Web Storage API の一種です。

主な特徴は以下の通りです。

  • 永続性: ブラウザを閉じたり、PC を再起動してもデータは消えません(明示的に消すまで残る)。
  • スコープ: オリジン ( Protocol + Domain + Port ) 単位で管理されます。 http://example.comhttps://example.com は別物として扱われます。
  • 容量: ブラウザによりますが、一般的に 5MB 程度まで保存可能です( Cookie4KB 程度)。
  • データ形式: キー ( Key )値 ( Value ) のペアで保存します。どちらも 文字列 ( String ) である必要があります。

sessionStorage との違い

よく比較される sessionStorage との最大の違いは 「データの寿命」 です。

機能 データの寿命 共有範囲 用途
localStorage 半永久的 (手動削除まで) 同一オリジンの全タブ・ウィンドウ 設定、カート情報、キャッシュ
sessionStorage タブを閉じるまで タブ内のみ 一時的な入力状態、画面遷移データ

2. 基本的な操作方法 (CRUD)

API は非常にシンプルです。 window.localStorage オブジェクト(または単に localStorage )を通して操作します。

データの保存 ( setItem )

// キー 'theme', 値 'dark' を保存
localStorage.setItem('theme', 'dark');

// 💡 注意: 数値を渡しても文字列に変換されます
localStorage.setItem('visitCount', 10); 
// 保存されるのは "10"

データの取得 ( getItem )

存在しないキーを指定した場合は null が返ります。

const currentTheme = localStorage.getItem('theme');
console.log(currentTheme); // "dark"

const userToken = localStorage.getItem('unknownKey');
console.log(userToken); // null

データの削除 ( removeItem / clear )

// 特定のキーを削除
localStorage.removeItem('theme');

// すべてのデータを削除(取り扱い注意!)
localStorage.clear();

3. 【重要】オブジェクトや配列を扱う方法

ここが初心者が最もハマるポイントです。 localStorage は文字列しか保存できないため、オブジェクトをそのまま保存しようとすると悲劇が起きます。

❌ 失敗例

const user = { id: 1, name: 'Taro' };
localStorage.setItem('user', user);

console.log(localStorage.getItem('user'));
// 出力: "[object Object]" 
// 😱 元のデータが消失し、単なる文字列になってしまう!

⭕️ 成功例: JSON 変換を使う

オブジェクトを保存する際は、シリアライズ ( Serialization )デシリアライズ ( Deserialization ) を行います。

  1. 保存時: JSON.stringify() で文字列化
  2. 取得時: JSON.parse() でオブジェクトに戻す
const user = { id: 1, name: 'Taro' };

// 1. 保存: オブジェクト -> JSON文字列
localStorage.setItem('user', JSON.stringify(user));

// 2. 取得: JSON文字列 -> オブジェクト
const savedData = localStorage.getItem('user');
if (savedData) {
  const parsedUser = JSON.parse(savedData);
  console.log(parsedUser.name); // "Taro"
}

4. 実務で使える Wrapper 関数の作成

実務では、毎回 JSON.parse を書くのは冗長ですし、エラーハンドリングも必要です(容量オーバー時などに例外が発生します)。
以下のような簡易的なラッパー関数を作っておくと便利です。

const StorageUtils = {
  // データを保存(try-catch で容量エラーをハンドリング)
  set: (key, value) => {
    try {
      const jsonValue = JSON.stringify(value);
      localStorage.setItem(key, jsonValue);
    } catch (e) {
      console.error('Storage quota exceeded or saving failed:', e);
    }
  },

  // データを取得(パースエラーをハンドリング)
  get: (key, defaultValue = null) => {
    try {
      const value = localStorage.getItem(key);
      return value ? JSON.parse(value) : defaultValue;
    } catch (e) {
      console.error('Error parsing storage data:', e);
      return defaultValue;
    }
  },
  
  remove: (key) => {
    localStorage.removeItem(key);
  }
};

// 【使用例】
StorageUtils.set('settings', { volume: 50, muted: false });
const settings = StorageUtils.get('settings', { volume: 0 }); // デフォルト値も指定可能

5. 注意点とベストプラクティス

便利ですが、銀の弾丸ではありません。以下の点に注意してください。

1. 機密情報を保存しない (Security)

localStorageJavaScript から容易にアクセス可能です。これは、クロスサイトスクリプティング ( XSS ) 脆弱性がある場合、攻撃者に中身を盗まれるリスクがあることを意味します。

  • NG: JWT トークン、パスワード、個人情報、API キー
  • OK: UI の設定(テーマ)、閲覧履歴、一時的なフォームデータ

2. 同期処理によるブロッキング (Performance)

localStorage の読み書きは 同期 ( Synchronous ) で行われます。つまり、巨大なデータを読み書きしている間、ブラウザの描画や操作が止まる可能性があります。
数 MB クラスのデータを扱う場合は、非同期で動作する IndexedDB の利用を検討してください。

3. ストレージイベントの活用

別タブで localStorage が更新された場合、storage イベントを検知して UI を同期させることができます。

window.addEventListener('storage', (event) => {
  if (event.key === 'theme') {
    // 別タブでテーマが変更されたら、このタブにも適用
    applyTheme(event.newValue);
  }
});

Conclusion

localStorage は、以下の要件を満たす場合に最適なソリューションです。

  • 永続性が必要
  • データ量が少ない (数 KB 〜 数 MB)
  • 機密情報ではない
  • 構造が単純 (Key-Value で管理可能)

「とりあえず Cookie」ではなく、用途に合わせて localStoragesessionStorage、そしてより高度な IndexedDB を使い分けることが、モダンな Web エンジニアへの第一歩です。まずは手元のプロジェクトで「ダークモードの実装」あたりから試してみてはいかがでしょうか?

Next Step

  • Chrome DevTools の Application タブを開き、現在閲覧しているサイトがどんなデータを Storage に保存しているか確認してみましょう。

References


⚠️ 本記事に関する注意

  • 本記事は執筆時点の情報に基づき作成しています。
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?