JavaScript | Web API:ストレージ系 API - JSON との組み合わせ

JavaScript JavaScript
スポンサーリンク

なぜ「ストレージ × JSON」がほぼセットなのか

localStorage / sessionStorage は、とてもシンプルなストレージです。
でも制約が一つあります——「保存できるのは文字列だけ」

一方、あなたが本当に扱いたいのは、オブジェクト・配列・数値・真偽値といった「構造を持ったデータ」です。
このギャップを埋めるために出てくるのが JSON です。

JSON は、
「オブジェクトや配列を文字列に変換して、また元に戻せるフォーマット」
と覚えておいて大丈夫です。

ストレージの世界は「キー → 文字列」
アプリの世界は「変数 → オブジェクト・配列」
この二つの世界をつなぐ橋が、JSON.stringifyJSON.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));
JavaScript

JSON.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

ここで大事なのは、
getItemnull を返す可能性があることと、
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,
};
JavaScript

SessionStorage に保存する

タブを閉じたら消えていい一時状態なので、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 を“道具として使いこなす側”に入っています。

タイトルとURLをコピーしました