JavaScriptの基礎 - Web Storage

2026年2月22日 (日) 06:11時点におけるWiki (トーク | 投稿記録)による版 (ページの作成:「== 概要 == Web Storage APIは、Webブラウザがキー・バリューペア形式のデータをクライアント側に保存するための仕組みである。<br> WHATWG HTML Web Storage仕様に基づいて実装されており、全ての主要なWebブラウザでサポートされている。<br> <br> Web Storageには、<u>localStorage</u> と <u>sessionStorage</u> の2つのオブジェクトが存在する。<br> <u>localStorage</u> はWebブラウザ…」)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

概要

Web Storage APIは、Webブラウザがキー・バリューペア形式のデータをクライアント側に保存するための仕組みである。
WHATWG HTML Web Storage仕様に基づいて実装されており、全ての主要なWebブラウザでサポートされている。

Web Storageには、localStoragesessionStorage の2つのオブジェクトが存在する。
localStorage はWebブラウザを閉じても永続的にデータを保存し、sessionStorage はタブを閉じるとデータが削除される。

Web Storage APIが保存できるデータは文字列のみである。
オブジェクトや配列を保存する場合は、JSON.stringify() で文字列に変換してから保存し、取得時に JSON.parse() で復元する必要がある。

他のストレージ手段との位置付けとして、Cookieはサーバとの通信に付随する小容量のストレージ (最大4[KB]) であり、IndexedDBは大容量・複雑なデータを扱うための非同期APIである。
Web Storageはこれら2つの中間に位置する手段であり、シンプルなキー・バリュー形式のデータを5〜10[MB]程度まで保存する用途に適している。


Web Storageの基本

localStorage と sessionStorageの違い

下表に、localStoragesessionStorage の主な違いを示す。

localStorage と sessionStorage の比較
項目 localStorage sessionStorage
ライフサイクル 明示的に削除するまで永続 タブ・ウィンドウを閉じると削除
スコープ 同じオリジンの全てのタブ・ウィンドウ 各タブ・ウィンドウで独立
容量 約5〜10[MB] 約5〜10[MB]
ページリロード 保持される 保持される
主な用途 ユーザ設定、テーマ設定、ログイン状態 フォーム入力の一時保存、ページ間の状態管理


sessionStorage は、タブを閉じると削除される点を除いてほぼ同じAPIを持つ。
ページのリロードや、Webブラウザの[戻る] / [進む]操作の後もデータは保持される。


データの保存と取得

Web Storage APIのメソッドは、localStoragesessionStorage のどちらでも共通して使用できる。
以下の説明では localStorage を例に示す。

setItem / getItem

setItem(key, value) は、指定したキーとバリューのペアを保存する。

キーが既に存在する場合はバリューが上書きされる。
キーとバリューはどちらも文字列として保存される。

getItem(key) は、指定したキーに対応するバリューを返す。
キーが存在しない場合は null を返す。

 // データの保存
 localStorage.setItem("username", "Alice");
 localStorage.setItem("theme", "dark");
 
 // データの取得
 const username = localStorage.getItem("username");
 console.log(username); // "Alice"
 
 // 存在しないキーの取得
 const missing = localStorage.getItem("nonExistentKey");
 console.log(missing); // null


ストレージの容量を超えた場合、setItem() は 例外 QuotaExceededError (DOMException) を発生させる。
エラーハンドリングを行う場合は、try...catch を使用する。

 function saveWithQuotaCheck(key, value) {
    try {
       localStorage.setItem(key, value);
    }
    catch (e) {
       if (e.name === "QuotaExceededError") {
          console.error("ストレージ容量が超過しました");
       }
    }
 }


removeItem / clear

removeItem(key) は、指定したキーとそのバリューをストレージから削除する。
指定したキーが存在しない場合は何も起こらない。

clear() は、ストレージ内の全てのキーを削除する。

 // 特定のキーを削除
 localStorage.removeItem("theme");
 
 // 全データを削除
 localStorage.clear();


key / length

length は読み取り専用プロパティで、ストレージに保存されているデータ項目の数を返す。

key(index) は、指定したインデックス (0始まり) に対応するキー名を返す。
インデックスが範囲外の場合は、null を返す。

key()length を組み合わせることにより、ストレージ内の全データをイテレーションできる。

 // ストレージ内の全てのキーをイテレーション
 for (let i = 0; i < localStorage.length; i++) {
    const key   = localStorage.key(i);
    const value = localStorage.getItem(key);
    console.log(`${key}: ${value}`);
 }



JSON変換

文字列のみ保存可能な理由

Web Storage APIの仕様上、キーとバリューはどちらも文字列型として保存される。
数値、真偽値、オブジェクト、配列等を直接保存しようとすると、自動的に文字列へ変換される。

例えば、数値 42 を保存すると文字列 "42" として保存されるため、取得後に数値として扱う場合は型変換が必要になる。
オブジェクトを直接保存すると "[object Object]" という文字列に変換され、元のデータを復元できなくなる。

このため、文字列以外のデータを保存する場合は JSON.stringify()JSON.parse() を使用する必要がある。

オブジェクトと配列の保存

オブジェクトや配列を保存する場合は、JSON.stringify() でJSON文字列に変換してから保存する。
取得時は JSON.parse() で元のデータ型に復元する。

 // オブジェクトの保存
 const userSettings = {
    theme: "dark",
    fontSize: 14,
    language: "ja",
 };
 localStorage.setItem("settings", JSON.stringify(userSettings));
 
 // オブジェクトの取得
 const savedSettings = JSON.parse(localStorage.getItem("settings"));
 console.log(savedSettings.theme); // "dark"
 
 // 配列の保存
 const bookmarks = ["page1", "page2", "page3"];
 localStorage.setItem("bookmarks", JSON.stringify(bookmarks));
 
 // 配列の取得
 const savedBookmarks = JSON.parse(localStorage.getItem("bookmarks"));
 console.log(savedBookmarks[0]); // "page1"


型情報の注意点

JSON.stringify() による変換では、一部のデータ型に関する情報が失われる点に注意が必要である。

下表に示す型は JSON変換で失われる または データが変化する。

JSON変換で失われる、またはデータが変化する型
説明
undefined (オブジェクトのプロパティ値) オブジェクトのプロパティ値が undefined の場合、そのプロパティはJSONに含まれない。
関数 (Function) 関数はJSONに変換されず、プロパティごと除外される。
シンボル (Symbol) シンボルはJSONに変換されず、プロパティごと除外される。
Date オブジェクト ISO 8601形式の文字列に変換される。
JSON.parse() 後は Date オブジェクトではなく文字列のままになる。
undefined (配列の要素) 配列内の undefined 要素は null に変換される。


Date オブジェクトを復元する場合は、JSON.parse() の第2引数にリバイバー関数を使用することで対応できる。

 // Dateオブジェクトを含むデータの保存
 const data = {
    name: "イベント",
    createdAt: new Date(),
 };
 
 localStorage.setItem("event", JSON.stringify(data));
 
 // リバイバー関数でDateを復元
 function dateReviver(key, value) {
    if (typeof value === "string") {
       const datePattern = /^\d{4}-\d{2}-\d{2}T/;
       if (datePattern.test(value)) {
          return new Date(value);
       }
    }
    return value;
 }
 
 const savedData = JSON.parse(localStorage.getItem("event"), dateReviver);
 console.log(savedData.createdAt instanceof Date); // true



storageイベント

他タブとの同期

storage イベントは、同じオリジンを共有する別のタブ・ウィンドウで localStorage に変更が加えられた場合に発生する。

変更を行ったタブ・ウィンドウ自身ではイベントは発生しないことに注意が必要である。

sessionStorage の変更は他のタブと共有されないため、storage イベントは発生しない。

下表に、StorageEvent オブジェクトのプロパティを示す。

StorageEventオブジェクトのプロパティ
プロパティ 説明
key 変更されたキー名
clear() が呼び出された場合は null になる。
oldValue 変更前の値
新規追加の場合は null になる。
newValue 変更後の値
削除の場合は null になる。
url ストレージ変更を引き起こしたドキュメントのURL
storageArea 変更が加えられた Storage オブジェクト
(localStorage または sessionStorage)


 // 他のタブからのlocalStorage変更を検知する
 window.addEventListener("storage", (event) => {
    console.log("変更されたキー:", event.key);
    console.log("前の値:", event.oldValue);
    console.log("新しい値:", event.newValue);
    console.log("変更元URL:", event.url);
 
    if (event.key === "theme") {
       // テーマが変更されたときの処理
       applyTheme(event.newValue);
    }
 });


この仕組みを利用することにより、複数タブ間でユーザ設定やログイン状態等を同期させることができる。


他のストレージ手段との比較

Cookie / IndexedDB / Web Storage の比較テーブル

主なクライアント側のストレージ手段の比較を以下に示す。

クライアントサイドストレージ比較
項目 Web Storage (localStorage / sessionStorage) Cookie IndexedDB
容量 5〜10[MB] 4[KB] 10[GB]以上
データ型 文字列のみ 文字列のみ オブジェクト・Blob等多様
API型 同期 同期 非同期
サーバへの自動送信 しない 全てのHTTPリクエストで自動送信 しない
インデックス・クエリ 不可 不可 可能
JavaScript以外のアクセス 不可 サーバ側からもアクセス可能 不可
有効期限設定 手動削除が必要 Expires / Max-Age属性で設定可能 手動削除が必要
HttpOnlyによるJSアクセス防止 不可 可能 不可
学習難度 低い 低〜中 高い
主な用途 設定・状態の簡易保存 認証・セッション管理 大容量データ・複雑なクエリ


Tauriアプリでの永続化手段

Tauriアプリケーションでは、WebViewの内部で動作するWeb Storageの他に、ネイティブ側のファイルシステムやデータベースを利用した永続化手段が提供されている。

Tauriアプリにおけるストレージ手段の比較
項目 Web Storage tauri-plugin-store tauri-plugin-sql
ストレージ方式 WebView内部 (文字列) ファイルシステム (JSON) データベース (SQL)
容量制限 3〜5[MB] 制限なし 制限なし
API型 同期 非同期 非同期
Rustからのアクセス 不可 可能 可能
データ型 文字列のみ 多様 (JSON対応) 多様 (SQL型)
主な用途 一時的なUI状態 アプリ設定・ユーザデータ リレーショナルデータ


tauri-plugin-store は、アプリ設定やユーザデータをファイルシステム上のJSONファイルに永続化するためのプラグインである。
Web Storageと比較して容量制限がなく、Rust側からもアクセスできる点が特徴である。

 import { Store } from "@tauri-apps/plugin-store";
 
 const store = new Store(".settings.json");
 
 // データの保存
 await store.set("apiKey", "secret-key-value");
 
 // データの取得
 const apiKey = await store.get("apiKey");
 console.log(apiKey); // "secret-key-value"


アプリ設定や機密性のないユーザデータの永続化には、tauri-plugin-store が適している。
Web Storageは一時的なUI状態の保持やRust側からのアクセスが不要な軽量なデータの保存に向いている。


セキュリティ上の注意事項

localStoragesessionStorage はJavaScriptから完全にアクセス可能であるため、
XSS (クロスサイトスクリプティング) 攻撃によって悪意あるスクリプトが格納データを読み取る可能性がある。

HTTP-only Cookieとは異なり、Web StorageにはJavaScriptベースの攻撃に対する組み込み保護機能がない。

以下の情報はWeb Storageに格納してはならない。

  • 認証トークン (JWT、セッションID)
  • APIキーやシークレット
  • パスワード
  • 個人識別情報 (PII)
  • 支払い情報


認証トークンはWeb Storageではなく、HTTP-only Cookieで管理することを推奨する。

セキュリティを向上させるために推奨される対策を以下に示す。

  • HTTP-only Cookieの使用
    セッション認証トークンの保管にはHTTP-only Cookieを使用する。
    JavaScriptからアクセスできないためXSSによる漏洩を防げる。

  • CSP (コンテンツセキュリティポリシー) の設定
    厳密なCSPを設定することで、不正なスクリプトの実行を防止する。

  • ログアウト時のストレージクリア
    ユーザがログアウトした時に localStorage.clear() を呼び出し、残存データを削除する。

  • HTTPSの使用
    通信の暗号化により、中間者攻撃によるデータ盗取を防止する。

  • サーバ側での入力検証・出力エスケープ
    XSSの根本的な原因となるスクリプトインジェクションをサーバ側で防止する。



関連情報