概要: localStorage
は、ウェブブラウザにデータを永続的に保存するための仕組みです。一度保存したデータは、ブラウザを閉じたりPCを再起動したりしても消えません。主に、ユーザーの設定や入力途中の情報など、ちょっとしたデータを保存するのに便利です。ただし、保存できるのは文字列データのみという点に注意が必要です。
主な特徴:
基本的な使い方:
データを保存するには localStorage.setItem('キー', '値')
を使います。
// 'userName' というキーで '田中太郎' という値を保存
localStorage.setItem('userName', '田中太郎');
保存したデータを取り出すには localStorage.getItem('キー')
を使います。
// 'userName' というキーの値を取り出す
const userName = localStorage.getItem('userName');
console.log(userName); // 出力: 田中太郎
ポイント:
localStorage
に保存するキーも値も、すべて文字列として扱われます。数値や真偽値を保存した場合も、取り出す際には文字列になっていることを覚えておきましょう。
概要: localStorage
を使いこなすために、主要なAPIメソッドと、データを安全かつ効果的に扱うための重要な注意点を学びます。特に、オブジェクトや配列の保存方法、エラーへの対処は必須の知識です。
localStorage
には、主に以下の5つのメソッドがあります。
setItem(key, value)
: 指定されたキー (key
) に値 (value
) を保存します。
key
: 保存するデータの名前(文字列)。value
: 保存するデータ(文字列)。localStorage.setItem('theme', 'dark');
localStorage.setItem('fontSize', '16'); // 数値も文字列として保存される
getItem(key)
: 指定されたキー (key
) に関連付けられた値を取得します。
null
を返します。const theme = localStorage.getItem('theme'); // 'dark'
const language = localStorage.getItem('language'); // 存在しないキーなので null
console.log(theme);
console.log(language);
removeItem(key)
: 指定されたキー (key
) とその値を削除します。
localStorage.removeItem('fontSize');
console.log(localStorage.getItem('fontSize')); // null (削除されたため)
clear()
: 現在のオリジン(ウェブサイト)の localStorage
に保存されている全てのキーと値を削除します。
localStorage.clear();
console.log(localStorage.getItem('theme')); // null (全て削除されたため)
注意:
clear()
は影響範囲が大きいので、本当に全てのデータを削除して良いか慎重に判断してください。
key(index)
: 指定されたインデックス (index
) にあるキーの名前を取得します。
0
から localStorage.length - 1
までの数値です。localStorage.length
で保存されているアイテムの総数を取得できます。localStorage.setItem('user', 'Alice');
localStorage.setItem('mode', 'editor');
for (let i = 0; i < localStorage.length; i++) {
const keyName = localStorage.key(i);
const value = localStorage.getItem(keyName);
console.log(`キー: ${keyName}, 値: ${value}`);
}
// 出力例 (順序は保証されません):
// キー: user, 値: Alice
// キー: mode, 値: editor
localStorage
は文字列しか保存できません。そのため、JavaScriptのオブジェクトや配列をそのまま保存しようとすると、意図しない結果になります(例: [object Object]
という文字列が保存される)。
オブジェクトや配列を正しく保存・復元するには、JSON
(JavaScript Object Notation) を利用します。
JSON.stringify()
を使ってオブジェクト/配列をJSON文字列に変換します。JSON.parse()
を使ってJSON文字列を元のオブジェクト/配列に戻します。const userSettings = {
theme: 'dark',
notifications: true,
favoriteColors: ['blue', 'green']
};
// 1. オブジェクトをJSON文字列に変換して保存
try {
const jsonString = JSON.stringify(userSettings);
localStorage.setItem('userSettings', jsonString);
} catch (error) {
console.error('設定の保存中にエラーが発生しました:', error);
// 保存失敗時の処理 (例: ユーザーに通知)
}
// 2. 保存されたJSON文字列を取得
const storedSettingsString = localStorage.getItem('userSettings');
// 3. JSON文字列をオブジェクトに復元 (nullチェックとエラーハンドリングを忘れずに)
let restoredSettings = null;
if (storedSettingsString) {
try {
restoredSettings = JSON.parse(storedSettingsString);
console.log('復元された設定:', restoredSettings);
console.log('テーマ:', restoredSettings.theme); // 'dark'
console.log('お気に入りの色(配列):', restoredSettings.favoriteColors); // ['blue', 'green']
} catch (error) {
console.error('設定の復元中にエラーが発生しました:', error);
// 復元失敗時の処理 (例: デフォルト設定を使用)
// localStorage.removeItem('userSettings'); // 不正なデータを削除することも検討
}
} else {
console.log('保存された設定はありません。');
}
より詳しいJSONの操作方法やエラーハンドリングについては、補足資料: JSON操作詳解 を参照してください。
localStorage
を利用する際は、いくつかのエラーケースを考慮する必要があります。
getItem()
時の null
チェック:
指定したキーが存在しない場合、getItem()
は null
を返します。null
に対して JSON.parse()
を実行しようとするとエラーになるため、必ず事前に null
でないことを確認しましょう。
const data = localStorage.getItem('possiblyNonExistentKey');
if (data !== null) {
// データが存在する場合の処理
const parsedData = JSON.parse(data); // ここでも try-catch を推奨
// ...
} else {
// データが存在しない場合の処理
}
JSON.parse()
時の SyntaxError
:
localStorage
から取得した文字列が、有効なJSON形式でない場合(例えば、データが破損していたり、手動で不正な値を設定した場合など)、JSON.parse()
は SyntaxError
というエラーを発生させます。これを防ぐには try...catch
ブロックで囲みます。
const potentiallyBrokenJson = localStorage.getItem('maybeBrokenData');
let parsedData;
if (potentiallyBrokenJson) {
try {
parsedData = JSON.parse(potentiallyBrokenJson);
} catch (e) {
console.error('JSON解析エラー:', e);
parsedData = null; // またはデフォルト値
// localStorage.removeItem('maybeBrokenData'); // 不正なデータを削除
}
}
setItem()
時の容量超過エラー (QuotaExceededError
):
localStorage
には保存容量の上限があります(通常はブラウザごとに5MB~10MB程度)。この上限を超えてデータを保存しようとすると、多くのブラウザで QuotaExceededError
(または類似のエラー) が発生し、保存に失敗します。これも try...catch
で捕捉できます。
const largeData = "a".repeat(10 * 1024 * 1024); // 約10MBの巨大な文字列
try {
localStorage.setItem('veryLargeData', largeData);
console.log('大きなデータを保存しました。');
} catch (e) {
if (e.name === 'QuotaExceededError' || e.message.toLowerCase().includes('quota')) {
console.error('localStorageの容量上限を超えました!');
// ユーザーに通知する、古いデータを削除するなど対策を検討
} else {
console.error('データの保存中に予期せぬエラーが発生しました:', e);
}
}
ポイント: 容量上限はブラウザや設定によって異なるため、大きなデータを保存する場合は特に注意が必要です。エラー発生時には、ユーザーに状況を伝えたり、不要なデータを削除するなどの対応を検討しましょう。
エラー処理の基本的な考え方や
try...catch
の使い方については、補足資料: try-catch詳解 も参考にしてください。
localStorage
の全ての操作(setItem
, getItem
, removeItem
, clear
, key
)は 同期的 (Synchronous) に実行されます。
同期的とは?
コードが書かれた順番に一つずつ実行され、一つの処理が終わるまで次の処理に進まない方式です。
localStorage.setItem('key', 'value');
というコードがあれば、この行の処理(データの保存)が完全に完了するまで、次の行のコードは実行されません。
メリット:
デメリット:
localStorage
の操作に時間がかかる場合(例えば、非常に大きなデータを読み書きする場合や、ディスクI/Oが遅い場合など)、その間ブラウザのメインスレッドがブロックされ、ウェブページの表示更新やユーザー操作への反応が停止してしまう(フリーズしたように見える)ことがあります。localStorage
に保存するデータは比較的小さいため、この問題が顕著になることは稀ですが、数MB単位の大きなデータを頻繁に読み書きするような場合は注意が必要です。目安として: 数KB程度の小さなデータの読み書きであれば、同期処理によるパフォーマンスへの影響はほとんど無視できます。しかし、アプリケーションの応答性が非常に重要な場合や、大きなデータを扱う可能性がある場合は、他の非同期ストレージAPI(例: IndexedDB)の利用も検討しましょう。詳細は 補足資料: ブラウザストレージ比較 を参照してください。
間違い1: localStorage
が利用可能か確認しない
localStorage
が無効になっているか、利用に制限がある場合があります。いきなり使おうとするとエラーになることがあります。localStorage
が存在し、機能するかをチェックする関数を用意すると良いでしょう。function isLocalStorageAvailable() {
try {
const testKey = '__testLocalStorageAvailability__';
localStorage.setItem(testKey, testKey);
localStorage.removeItem(testKey);
return true;
} catch (e) {
return false;
}
}
if (isLocalStorageAvailable()) {
// localStorageが利用可能な場合の処理
localStorage.setItem('myKey', 'myValue');
} else {
console.warn('localStorageは利用できません。');
// 代替手段を検討するか、ユーザーに通知
}
間違い2: オブジェクトや配列を直接保存しようとする
JSON.stringify()
を使わずにオブジェクトを保存すると "[object Object]"
のような文字列が保存されてしまいます。JSON.stringify()
で文字列化してから保存し、JSON.parse()
で復元します。間違い3: getItem()
の結果が null
である可能性を考慮しない
getItem()
は null
を返します。null
に対して JSON.parse()
を行うとエラーになります。getItem()
の結果を必ずチェックし、null
でない場合のみ JSON.parse()
を行います。間違い4: キーの衝突
myapp_userSettings
)、またはキーの命名規則を明確に定めることで衝突を避けます。ベストプラクティス1: 必要なデータのみを保存する
localStorage
の容量は有限です。本当に必要な最小限のデータのみを保存するように心がけましょう。ベストプラクティス2: 適切なエラーハンドリングを行う
try...catch
を使って、保存時(容量超過など)や読み込み時(JSON解析エラーなど)のエラーを適切に処理し、アプリケーションがクラッシュしないようにします。ベストプラクティス3: 機密情報を保存しない
localStorage
のデータは暗号化されず、ブラウザの開発者ツールなどから容易にアクセス可能です。パスワードや個人情報などの機密情報は絶対に保存しないでください。概要: localStorage
をより深く理解し、安全かつ効果的に活用するための追加知識や、関連するブラウザ技術について解説します。
localStorage
は手軽で便利ですが、セキュリティ面では注意が必要です。
XSS (クロスサイトスクリプティング) のリスク:
localStorage
に保存されたデータにアクセスし、それを盗み出したり改ざしたりすることができます。機密情報の保存は避ける:
localStorage
のデータは暗号化されず、ブラウザの開発者ツールを使えば誰でも簡単に見ることができます。HTTPSの利用:
localStorage
のデータ自体はHTTPSで暗号化されるわけではありませんが、ウェブサイト全体をHTTPSで提供することで、通信経路上でのデータの盗聴や改ざんを防ぐことができます。これは localStorage
に限らず、ウェブセキュリティの基本です。localStorage
の操作は同期的であるため、使い方によってはパフォーマンスに影響を与える可能性があります。
setItem()
を呼び出すような処理は避けましょう。データをまとめて一度に保存する方が効率的です。localStorage
から多くのデータを読み込んで処理する場合、ページの表示開始が遅れる可能性があります。必要なデータだけを効率的に読み込むようにしましょう。
localStorage
のパフォーマンスを最大限に引き出すための具体的なテクニックや、他のストレージとの比較については、補足資料: localStorage_パフォーマンス で詳しく解説しています。
StorageEvent
による変更の監視localStorage
や sessionStorage
のデータが変更されたとき、同じオリジンの他のウィンドウ(またはタブ)でその変更を検知できる仕組みとして StorageEvent
があります。
仕組み:
localStorage.setItem()
, removeItem()
, clear()
が実行されると、同じオリジンを開いている他の全てのウィンドウの window
オブジェクトに対して storage
イベントが発生します。イベントオブジェクトのプロパティ:
event.key
: 変更されたアイテムのキー名 (clear()
の場合は null
)。event.oldValue
: 変更前の値 (setItem()
で新規追加の場合は null
)。event.newValue
: 変更後の値 (removeItem()
の場合は null
)。event.url
(または event.uri
): 変更が発生したページのURL。event.storageArea
: 変更が発生した Storage
オブジェクト (localStorage
または sessionStorage
)。コード例:
// 他のウィンドウ/タブでのlocalStorageの変更を監視
window.addEventListener('storage', function(event) {
console.log('ストレージが変更されました!');
console.log('キー:', event.key);
console.log('古い値:', event.oldValue);
console.log('新しい値:', event.newValue);
console.log('URL:', event.url);
console.log('ストレージエリア:', event.storageArea);
if (event.key === 'userLoginStatus' && event.newValue === 'loggedOut') {
// 他のタブでログアウトされたら、このタブもログアウト処理を行うなど
alert('他のタブでログアウトされました。このページも更新します。');
window.location.reload();
}
});
ユースケース例:
ブラウザには localStorage
以外にもデータを保存する仕組みがあります。それぞれの特徴を理解し、用途に応じて使い分けることが重要です。
特徴 | localStorage |
sessionStorage |
Cookie |
IndexedDB |
---|---|---|---|---|
データの永続性 | ブラウザを閉じても残る | タブ/ウィンドウを閉じると消える | 有効期限を設定可能、サーバーにも送信される | ブラウザを閉じても残る |
容量 | 通常 5-10MB | 通常 5-10MB | 約4KB | 大容量 (数GB単位も可能、ユーザーの許可が必要な場合あり) |
APIの種類 | 同期API (シンプル) | 同期API (シンプル) | 同期API (操作がやや煩雑) | 非同期API (高機能だが複雑) |
主な用途 | 永続的なユーザー設定、オフラインデータの一部など | 一時的なフォーム入力内容、ページ間の短期的な状態保持 | 認証トークン、セッション管理、トラッキング (サーバーとの連携が主) | 大量の構造化データ、オフラインアプリケーションのメインデータストア、高度な検索 |
サーバー送信 | 自動送信されない | 自動送信されない | 各HTTPリクエストで自動送信される | 自動送信されない |
データ形式 | 文字列のみ | 文字列のみ | 文字列のみ | JavaScriptオブジェクト、ファイルなど多様 |
各ストレージ技術のより詳細な比較、メリット・デメリット、具体的な使い分けのシナリオについては、補足資料: ブラウザストレージ比較 を参照してください。
概要: localStorage
を使って、実際のウェブアプリケーションで役立つ簡単な機能を実装する例を見ていきましょう。ここでは、ユーザーの見た目の設定(例:ダークモードのON/OFF)を保存し、次回アクセス時にもその設定を復元する機能を考えます。
多くのウェブサイトで提供されているダークモード/ライトモードの切り替え機能を localStorage
を使って実装してみましょう。
HTMLの準備 (例):
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-UTF-8">
<title>ダークモードデモ</title>
<style>
body {
transition: background-color 0.3s, color 0.3s;
}
body.dark-mode {
background-color: #333;
color: #f0f0f0;
}
.container { padding: 20px; }
button { padding: 10px; cursor: pointer; }
</style>
</head>
<body>
<div class="container">
<h1>ダークモード設定</h1>
<p>現在のモード: <span id="currentMode">ライト</span></p>
<button id="toggleModeButton">モード切り替え</button>
</div>
<script>
// JavaScriptコードはここに記述
</script>
</body>
</html>
JavaScriptの実装:
document.addEventListener('DOMContentLoaded', function() {
const toggleButton = document.getElementById('toggleModeButton');
const currentModeSpan = document.getElementById('currentMode');
const body = document.body;
const storageKey = 'darkModePreference'; // localStorageのキー
// 1. ページ読み込み時にlocalStorageから設定を読み込む
function applySavedPreference() {
try {
const savedMode = localStorage.getItem(storageKey);
if (savedMode === 'dark') {
body.classList.add('dark-mode');
currentModeSpan.textContent = 'ダーク';
} else {
// 'light' または null (未設定) の場合はライトモード
body.classList.remove('dark-mode');
currentModeSpan.textContent = 'ライト';
}
} catch (e) {
console.error('設定の読み込みに失敗しました:', e);
// エラー時はデフォルト(ライトモード)のまま
body.classList.remove('dark-mode');
currentModeSpan.textContent = 'ライト';
}
}
// 2. モード切り替えボタンのイベントリスナー
toggleButton.addEventListener('click', function() {
body.classList.toggle('dark-mode');
let newMode = 'light';
if (body.classList.contains('dark-mode')) {
newMode = 'dark';
}
currentModeSpan.textContent = (newMode === 'dark') ? 'ダーク' : 'ライト';
// 3. 変更された設定をlocalStorageに保存
try {
localStorage.setItem(storageKey, newMode);
} catch (e) {
console.error('設定の保存に失敗しました:', e);
alert('設定の保存に失敗しました。localStorageの容量がいっぱいか、利用できない状態かもしれません。');
}
});
// 初期表示時に保存された設定を適用
applySavedPreference();
});
解説:
applySavedPreference
関数:DOMContentLoaded
イベント後)に実行されます。localStorage.getItem(storageKey)
で 'darkModePreference'
というキーに保存された値を取得します。'dark'
であれば、body
要素に dark-mode
クラスを追加してダークモードのスタイルを適用し、表示も更新します。'light'
または保存された値がない null
の場合)はライトモードにします。localStorage
へのアクセスは try...catch
で囲み、万が一エラーが発生してもページがクラッシュしないようにします。toggleModeButton
がクリックされると、body
の dark-mode
クラスを切り替えます。'dark'
または 'light'
)を判定し、localStorage.setItem(storageKey, newMode)
で新しい設定を保存します。localStorage
への保存処理は try...catch
で囲みます。容量超過などのエラーが発生した場合に備え、ユーザーに通知することも検討できます。この例のように、localStorage
を使うことで、ユーザーが一度設定した見た目のモードを記憶しておき、次回訪問時にも同じモードで表示することができます。
ポイント: このようなページ初期化時の処理パターンは非常によく使われます。詳細は 補足資料: ページ初期化パターン も参考にしてください。
ブログサイトなどで、ユーザーが最後に閲覧した記事のIDを localStorage
に保存しておき、次回訪問時に「前回閲覧した記事はこちら」といった形で表示する機能を考えてみましょう。
記事ページ (article.html - 概念的な例):
// (記事ページ article.html?id=123 などで実行される想定)
// 現在の記事IDを取得 (URLなどから)
const currentArticleId = new URLSearchParams(window.location.search).get('id');
const storageKey = 'lastViewedArticleId';
if (currentArticleId) {
try {
// 現在の記事IDをlocalStorageに保存
localStorage.setItem(storageKey, currentArticleId);
console.log(`最後に閲覧した記事ID (${currentArticleId}) を保存しました。`);
} catch (e) {
console.error('記事IDの保存に失敗しました:', e);
}
}
トップページ (index.html - 概念的な例):
// (トップページ index.html などで実行される想定)
document.addEventListener('DOMContentLoaded', function() {
const lastViewedArticleIdKey = 'lastViewedArticleId';
const lastViewedLinkContainer = document.getElementById('lastViewedLinkContainer'); // HTMLに <div id="lastViewedLinkContainer"></div> がある想定
try {
const lastArticleId = localStorage.getItem(lastViewedArticleIdKey);
if (lastArticleId && lastViewedLinkContainer) {
const link = document.createElement('a');
link.href = `/article.html?id=${lastArticleId}`; // 適切な記事URLに
link.textContent = `前回閲覧した記事 (ID: ${lastArticleId}) をもう一度読む`;
lastViewedLinkContainer.appendChild(link);
}
} catch (e) {
console.error('前回閲覧記事の読み込みに失敗しました:', e);
}
});
解説:
localStorage
に lastViewedArticleId
というキーで保存します。localStorage
から lastViewedArticleId
を取得し、もし存在すれば、その記事へのリンクをページ内に動的に生成して表示します。このように、localStorage
はユーザーのちょっとした行動履歴や状態を記憶しておくのに役立ちます。ただし、保存するデータの内容や量、セキュリティには常に注意を払いましょう。
この資料で解説した内容をより深く理解するために、以下の補足資料も合わせてお読みいただくことをお勧めします。
localStorage
でオブジェクトや配列を扱う際に必須となる JSON.stringify()
と JSON.parse()
の詳細な使い方、エラーハンドリングについて解説しています。localStorage
の操作(特に容量超過やJSON解析時)で発生しうるエラーを適切に処理するための try...catch
構文について詳しく解説しています。localStorage
以外にもある sessionStorage
, Cookie
, IndexedDB
といったブラウザストレージ技術との違い、それぞれのメリット・デメリット、使い分けのシナリオを詳細に比較しています。localStorage
の同期的な性質がパフォーマンスに与える影響や、大量データ利用時の注意点、最適化のテクニックについて解説しています。localStorage
などから設定を読み込んで初期状態を復元する、といった一般的な処理の流れやベストプラクティスを紹介しています。localStorage
に保存するデータの構造やバージョン管理など、データの整合性を保つための考え方について触れています。localStorage
でJSONを介してオブジェクトを扱う際の基礎となる、JavaScriptのオブジェクトについてより詳しく学べます。StorageEvent
のように、ブラウザで発生するイベントを扱うための基本的な知識を深めることができます。これらの資料を通じて、localStorage
をはじめとするブラウザの機能をより効果的かつ安全に活用できるようになることを目指しましょう。