なぜ「ストレージ × JSON」がほぼセットなのか
localStorage / sessionStorage は、とてもシンプルなストレージです。
でも制約が一つあります——「保存できるのは文字列だけ」。
一方、あなたが本当に扱いたいのは、オブジェクト・配列・数値・真偽値といった「構造を持ったデータ」です。
このギャップを埋めるために出てくるのが JSON です。
JSON は、
「オブジェクトや配列を文字列に変換して、また元に戻せるフォーマット」
と覚えておいて大丈夫です。
ストレージの世界は「キー → 文字列」
アプリの世界は「変数 → オブジェクト・配列」
この二つの世界をつなぐ橋が、JSON.stringify と JSON.parse です。
JSON.stringify と JSON.parse の役割をしっかり押さえる
JSON.stringify は「オブジェクト → JSON文字列」
JSON.stringify は、JavaScript の値(オブジェクト・配列など)を
JSON 形式の文字列に変換します。
const user = { name: "taro", age: 20 };
const json = JSON.stringify(user);
console.log(json); // '{"name":"taro","age":20}'
console.log(typeof json); // "string"
JavaScriptここで重要なのは、json はただの文字列なので、そのままストレージに保存できるということです。
localStorage.setItem("user", JSON.stringify(user));
JavaScriptJSON.parse は「JSON文字列 → オブジェクト」
JSON.parse は、JSON.stringify の逆です。
JSON 形式の文字列を、元のオブジェクトや配列に戻します。
const json = '{"name":"taro","age":20}';
const user = JSON.parse(json);
console.log(user.name); // "taro"
console.log(user.age); // 20
JavaScriptストレージから取り出した文字列を JSON.parse すれば、
アプリの中で普通のオブジェクトとして扱えます。
const userJson = localStorage.getItem("user");
if (userJson !== null) {
const user = JSON.parse(userJson);
console.log(user.name);
}
JavaScript「二つの世界を行き来するゲート」というイメージ
ここをイメージでつかんでほしいです。
ストレージの世界
キーと文字列だけが存在する、すごく単純な世界。
アプリの世界
オブジェクト・配列・数値・真偽値が自由に動き回る世界。
JSON.stringify は「アプリの世界 → ストレージの世界」へのゲート。JSON.parse は「ストレージの世界 → アプリの世界」へのゲート。
この感覚があると、「なんで毎回 stringify / parse するの?」がスッと腑に落ちます。
具体例1:TODOリストを JSON で保存する
アプリ側のデータ構造を決める
TODO リストを配列で管理するとします。
let todos = [
{ text: "牛乳を買う", done: false },
{ text: "メールを返す", done: true },
];
JavaScriptこのままでは localStorage に保存できません。
でも、JSON にすれば保存できます。
保存するときの流れ
配列 → JSON文字列 → setItem
という流れにします。
function saveTodos(todos) {
const json = JSON.stringify(todos);
localStorage.setItem("todos", json);
}
JavaScriptここでやっているのは、
「アプリの世界の配列を、ストレージの世界の文字列に変換して渡す」ことです。
読み込むときの流れ
getItem → JSON文字列 → 配列
という逆の流れです。
function loadTodos() {
const json = localStorage.getItem("todos");
if (json === null) {
return [];
}
try {
const todos = JSON.parse(json);
if (!Array.isArray(todos)) {
return [];
}
return todos;
} catch {
return [];
}
}
JavaScriptここで大事なのは、getItem が null を返す可能性があることと、JSON.parse が失敗する可能性を try/catch で受けていることです。
アプリ側では、こう使えます。
let todos = loadTodos();
function addTodo(text) {
todos.push({ text, done: false });
saveTodos(todos);
}
JavaScript具体例2:ユーザー設定(テーマ・言語)を JSON でまとめて保存する
設定を一つのオブジェクトにまとめる
例えば、ユーザー設定をこう持つとします。
const settings = {
theme: "dark",
language: "ja",
showTips: true,
};
JavaScriptこれをバラバラに保存することもできますが、
JSON を使えば「設定オブジェクト」として一括で保存できます。
保存する関数
function saveSettings(settings) {
const json = JSON.stringify(settings);
localStorage.setItem("settings", json);
}
JavaScript読み込む関数
function loadSettings() {
const json = localStorage.getItem("settings");
if (json === null) {
return {
theme: "light",
language: "ja",
showTips: true,
};
}
try {
const settings = JSON.parse(json);
return {
theme: settings.theme ?? "light",
language: settings.language ?? "ja",
showTips: settings.showTips ?? true,
};
} catch {
return {
theme: "light",
language: "ja",
showTips: true,
};
}
}
JavaScriptここでやっていることは、
「ストレージの中身が壊れていても、アプリが落ちないようにデフォルトを用意する」ことです。
JSON とストレージを組み合わせるとき、
「パースに失敗したらどうするか」まで考えられると、一気にプロっぽくなります。
具体例3:SessionStorage と JSON で「タブごとの一時状態」を持つ
タブごとの一時状態をオブジェクトで持つ
例えば、ページ内のフィルター状態をこう持つとします。
let filterState = {
keyword: "",
sortBy: "date",
onlyDone: false,
};
JavaScriptSessionStorage に保存する
タブを閉じたら消えていい一時状態なので、sessionStorage を使います。
function saveFilterState(state) {
sessionStorage.setItem("filterState", JSON.stringify(state));
}
JavaScript読み込む
function loadFilterState() {
const json = sessionStorage.getItem("filterState");
if (json === null) {
return {
keyword: "",
sortBy: "date",
onlyDone: false,
};
}
try {
const state = JSON.parse(json);
return {
keyword: state.keyword ?? "",
sortBy: state.sortBy ?? "date",
onlyDone: state.onlyDone ?? false,
};
} catch {
return {
keyword: "",
sortBy: "date",
onlyDone: false,
};
}
}
JavaScriptこれで、
同じサイトを複数タブで開いても、
タブごとに別々のフィルター状態を持てます。
JSON は、
「一つのまとまりとして扱いたい状態」を
そのままストレージに出し入れするのに向いています。
よくある落とし穴と、その乗り越え方
stringify / parse を忘れて「[object Object]」になる問題
オブジェクトをそのまま setItem に渡すと、こうなります。
const user = { name: "taro" };
localStorage.setItem("user", user);
JavaScript実際に保存されるのは "[object Object]" という文字列です。JSON.parse しても元には戻せません。
この問題は、
「ストレージは文字列しか持てない」
「オブジェクトは必ず JSON.stringify する」
というルールを体に染み込ませることで防げます。
JSON.parse が失敗したときにアプリが落ちる問題
JSON.parse は、変な文字列を渡すと例外を投げます。
JSON.parse("これは JSON ではない"); // SyntaxError
JavaScriptストレージの中身が何らかの理由で壊れていた場合、
そのまま JSON.parse するとアプリが落ちます。
なので、ストレージから読み込むときは
「失敗したらどうするか」を決めておくのが大事です。
function safeParse(json, defaultValue) {
try {
return JSON.parse(json);
} catch {
return defaultValue;
}
}
JavaScriptこういう小さなユーティリティを作っておくのも、
「JSON × ストレージ」を扱うプロっぽい書き方です。
初心者として「JSON × ストレージ」で本当に意識してほしいこと
最後に、あなたの頭の中に置いておいてほしい問いをまとめます。
ストレージは「文字列だけの世界」、アプリは「オブジェクトの世界」として分けて考えられているか。JSON.stringify を「アプリ → ストレージ」のゲート、JSON.parse を「ストレージ → アプリ」のゲートとしてイメージできているか。
オブジェクトや配列を保存するときに、毎回 stringify / parse をセットで書けているか。getItem が null を返す場合、JSON.parse が失敗する場合をちゃんと想定できているか。
「アプリの状態を一つのオブジェクトにまとめて JSON で保存する」という発想を持てているか。
おすすめの練習は、
小さなアプリ(TODO、設定画面、簡単なメモ帳など)を作って、
状態はオブジェクト・配列で管理する
保存・読み込みのときだけ JSON を意識する
という形で書いてみることです。
「ストレージに“生のオブジェクト”を突っ込む」のではなく、
「JSON を通して、二つの世界を行き来させる」
という感覚が身についたとき、
あなたはもうストレージ系 API を“道具として使いこなす側”に入っています。
