Day 48:JSONとlocalStorage
Day 48では、第4フェーズ「ブラウザデータ保存」をさらに一歩進めて、JSON と localStorage を組み合わせる方法を学びます。Day 46では localStorage の基本として、setItem()、getItem()、removeItem() を学びました。Day 47では、入力データを保存し、ページ更新後も表示する実践を通して、「保存する処理」と「読み込み時に表示する処理」は別だという大切な考え方も確認しました。Day 48ではその続きとして、文字列だけでなく、配列やオブジェクトのような複雑なデータをどうやって保存するのかを学びます。
ここが非常に重要な理由は、実際のアプリでは保存したいデータが単なる1つの文字列ではないことが多いからです。たとえばToDoアプリを考えると、保存したいのは1件の文字だけではなく、複数のToDo項目です。さらに、ToDo1件ごとに「内容」や「完了したかどうか」といった情報も持たせたくなります。つまり、配列やオブジェクトを保存できないと、アプリを本格的に保存対応させるのが難しくなります。
しかし、ここで初心者の方が必ずぶつかるのが、localStorage は文字列しか保存できないという壁です。だからこそ JSON が必要になります。今回のDay 48では、この考え方を丁寧にかみ砕きながら、配列の保存、オブジェクトの保存、そして実践としてToDoデータ保存までつなげていきます。用語だけを覚えるのではなく、「なぜJSONが必要なのか」「どのタイミングで文字列化し、どのタイミングで元に戻すのか」を流れで理解することが大切です。
まず最初に理解したいこと
今回の学習で一番大切なのは、localStorage はそのままでは配列やオブジェクトをきれいに保存できない、ということです。Day 46でも少し触れたように、localStorage に保存される値は基本的に文字列です。つまり、配列やオブジェクトを保存したいなら、いったん文字列に変換する必要があります。そして、取り出したあとには再び配列やオブジェクトとして使える形に戻す必要があります。
この「保存前に文字列へ変換」「読み込み後に元の形へ復元」という考え方が、Day 48の中心です。初心者の方は、ここを難しい変換処理として見るのではなく、「保存しやすい形に変えてからしまい、使うときに元に戻す」と考えると理解しやすいです。
JSONとは何か
JSON は、データを文字列の形で表現するための形式です。JavaScriptでは、配列やオブジェクトを保存や送受信しやすくするためによく使われます。正式には JavaScript Object Notation の略ですが、初心者の段階では、まず「配列やオブジェクトを文字列にするための便利な形式」と理解すれば十分です。
たとえば、次のようなJavaScriptの配列があるとします。
const fruits = ["りんご", "みかん", "ぶどう"];JavaScriptこれをJSON文字列にすると、見た目は次のようになります。
'["りんご","みかん","ぶどう"]'JavaScriptまた、オブジェクトならこうです。
const user = {
name: "Taro",
age: 20
};JavaScriptこれをJSON文字列にすると、次のようになります。
'{"name":"Taro","age":20}'JavaScriptこのように、JSONは「配列やオブジェクトを文字列として持ち運べる形」にしてくれます。初心者の方は、JSONを「保存や送信のための変換後の姿」と考えるとわかりやすいです。
なぜJSONが必要なのか
ここは非常に大切です。なぜJSONが必要なのかというと、localStorage が文字列しか保存できないからです。たとえば、配列をそのまま保存しようとしても、思った通りに扱えないことがあります。
const fruits = ["りんご", "みかん", "ぶどう"];
localStorage.setItem("fruits", fruits);JavaScriptこれでも一見保存できたように見えますが、あとで取り出すと、元の配列としては扱いにくくなります。オブジェクトの場合は特に問題が大きく、そのまま保存すると期待通りの形にならないことがあります。
そのため、きちんと配列やオブジェクトを保存したいときは、JSON.stringify() で文字列に変換してから保存し、JSON.parse() で元に戻して使います。これがDay 48の大事な基本です。
JSON.stringify() とは何か
JSON.stringify() は、JavaScriptの配列やオブジェクトをJSON文字列に変換するためのメソッドです。保存前に使います。
書き方は次の通りです。
JSON.stringify(データ)JavaScriptたとえば、配列を変換するならこうです。
const fruits = ["りんご", "みかん", "ぶどう"];
// 配列を JSON 文字列に変換する
const fruitsJson = JSON.stringify(fruits);
console.log(fruitsJson);JavaScriptこの結果は、配列ではなくJSON形式の文字列になります。つまり、localStorage に保存しやすい姿になったということです。
初心者の方は、stringify を「文字列化する」と覚えるとよいです。名前の通り、データを文字列へ変える処理です。
JSON.parse() とは何か
JSON.parse() は、JSON文字列を元の配列やオブジェクトに戻すためのメソッドです。読み込み後に使います。
書き方は次の通りです。
JSON.parse(JSON文字列)JavaScriptたとえば、先ほどのJSON文字列を元の配列へ戻すならこうです。
const fruitsJson = '["りんご","みかん","ぶどう"]';
// JSON 文字列を配列に戻す
const fruits = JSON.parse(fruitsJson);
console.log(fruits);JavaScriptこれで、再びJavaScriptの配列として使えるようになります。初心者の方は、parse を「元の形に戻す」と覚えるとわかりやすいです。stringify と parse はセットで使うことが非常に多いです。
保存の流れをまず1本にする
ここまでをまとめると、配列やオブジェクトを localStorage に保存するときの基本の流れは次のようになります。
- JavaScriptの配列やオブジェクトを用意する
- `JSON.stringify()` で文字列に変換する
- `localStorage.setItem()` で保存する
- `localStorage.getItem()` で取り出す
- `JSON.parse()` で元の配列やオブジェクトに戻す
この5ステップがとても大切です。初心者の方は、Day 48ではこの流れを日本語で説明できるようになることを目標にすると理解が深まりやすいです。
配列を保存する方法
では、まずは配列の保存から見ていきます。たとえば、好きな果物の一覧を配列として保存する例です。
// 配列を用意する
const fruits = ["りんご", "みかん", "ぶどう"];
// JSON 文字列に変換して保存する
localStorage.setItem("fruits", JSON.stringify(fruits));JavaScriptこのコードでは、fruits 配列をそのまま保存するのではなく、JSON.stringify(fruits) で文字列に変換してから保存しています。ここが最重要ポイントです。
次に、取り出すときはこうなります。
// localStorage から取り出す
const savedFruits = localStorage.getItem("fruits");
// JSON 文字列を配列に戻す
const fruitsArray = JSON.parse(savedFruits);
console.log(fruitsArray);JavaScriptこれで、再びJavaScriptの配列として使えるようになります。初心者の方は、「保存するときは stringify」「取り出したら parse」とセットで覚えるとよいです。
配列保存で特に注意したいこと
ここで大事なのは、localStorage.getItem() の結果が null の場合もあるということです。まだ保存されていない場合に JSON.parse(null) をすると注意が必要です。そのため、保存データがあるかを確認してから使うのが安全です。
たとえば、次のように書けます。
// localStorage から取り出す
const savedFruits = localStorage.getItem("fruits");
// 保存データがあるか確認する
if (savedFruits !== null) {
const fruitsArray = JSON.parse(savedFruits);
console.log(fruitsArray);
} else {
console.log("果物データは保存されていません。");
}JavaScript初心者の方は、localStorage と JSON.parse() を使うときは「そもそもデータがあるか」を確認する習慣をつけると安全です。
オブジェクトを保存する方法
次に、オブジェクトの保存です。たとえば、名前と年齢を持つユーザー情報を保存したいとします。
// オブジェクトを用意する
const user = {
name: "Taro",
age: 20
};
// JSON 文字列に変換して保存する
localStorage.setItem("user", JSON.stringify(user));JavaScript取り出すときはこうです。
// localStorage から取り出す
const savedUser = localStorage.getItem("user");
// JSON 文字列をオブジェクトに戻す
const userObject = JSON.parse(savedUser);
console.log(userObject.name);
console.log(userObject.age);JavaScriptこのように、オブジェクトも配列と同じ流れで扱えます。初心者の方は、「配列でもオブジェクトでも、保存方法の基本は同じ」と整理すると理解しやすいです。
配列とオブジェクトの違いをここで整理する
Day 48では、配列とオブジェクトの違いも少し意識しておくとよいです。配列は複数のデータを順番に並べるのに向いています。一方、オブジェクトは1つのデータに複数の情報を持たせるのに向いています。
たとえばToDoアプリなら、
- ToDoの一覧全体は配列で持つのが自然です。
- ToDo1件ごとの情報はオブジェクトで持つのが自然です。
これは非常に大切です。なぜなら、今回の実践「ToDoデータ保存」では、この2つを組み合わせて使うからです。
ToDoデータをどう表現するか
では、ToDoアプリの保存データをどう考えればよいでしょうか。初心者向けに言うと、ToDoアプリには「複数のToDo」があります。だから全体は配列です。そして、1つ1つのToDoには「やることの内容」や「完了したかどうか」といった情報があります。だから1件ごとはオブジェクトです。
たとえば、次のような形です。
const todos = [
{ text: "買い物に行く", completed: false },
{ text: "JavaScriptを勉強する", completed: true }
];JavaScriptこの形は非常に重要です。
- `todos` 全体は配列です。
- 中の1つ1つはオブジェクトです。
- `text` がToDo内容です。
- `completed` が完了状態です。
初心者の方は、ここで「配列の中にオブジェクトが入る」という形をしっかり意識すると、今後のアプリ開発でもとても役立ちます。
ToDoデータ保存の基本の流れ
ToDoデータを保存する流れは、次のようになります。
- ToDo一覧を配列で持つ
- ToDoを追加したら配列に新しいオブジェクトを入れる
- その配列を `JSON.stringify()` して `localStorage` に保存する
- ページ読み込み時に `localStorage` から取り出す
- `JSON.parse()` で元の配列に戻す
- 配列の内容を画面に表示する
この流れはDay 47より少しだけ複雑ですが、基本の考え方は同じです。違うのは、保存するデータが単なる文字列ではなく、配列とオブジェクトになっていることです。
まずはToDo配列を保存する小さな例
最初に、画面表示をまだ考えず、ToDo配列を保存するだけの例を見てみます。
// ToDo 配列を用意する
const todos = [
{ text: "牛乳を買う", completed: false },
{ text: "本を読む", completed: true }
];
// JSON 文字列に変換して保存する
localStorage.setItem("todos", JSON.stringify(todos));JavaScript取り出すときはこうです。
// localStorage から取り出す
const savedTodos = localStorage.getItem("todos");
// データがあれば配列に戻す
if (savedTodos !== null) {
const todosArray = JSON.parse(savedTodos);
console.log(todosArray);
}JavaScriptこれで、ToDo一覧全体を丸ごと保存・復元できます。初心者の方は、まずこの段階で「ToDo配列も保存できるのだな」とつかめれば十分です。
実践:ToDoデータ保存アプリを作る
ここから、実際に入力したToDoを保存し、ページ更新後も表示される簡単なアプリを作ります。今回は、まずToDo追加と保存、読み込み表示までに絞ります。完了切り替えや削除を完全に保存対応にするのは今後の発展として考えられますが、Day 48では「配列とオブジェクトを使ってToDoを保存する」ことが主な目標です。
まずHTMLです。
<h2>ToDoデータ保存アプリ</h2>
<input type="text" id="todoInput" placeholder="ToDoを入力してください">
<button id="addButton">追加</button>
<ul id="todoList"></ul>
次にJavaScriptです。
// 必要な要素を取得する
const todoInput = document.getElementById("todoInput");
const addButton = document.getElementById("addButton");
const todoList = document.getElementById("todoList");
// localStorage から保存された ToDo を取得する
const savedTodos = localStorage.getItem("todos");
// 保存データがあれば配列に戻し、なければ空配列にする
let todos = savedTodos !== null ? JSON.parse(savedTodos) : [];
// ToDo を画面に表示する関数
function renderTodos() {
// いったんリストを空にする
todoList.innerHTML = "";
// 配列の内容を順番に表示する
for (const todo of todos) {
// li 要素を作る
const li = document.createElement("li");
// ToDo の文字を表示する
li.textContent = todo.text;
// リストに追加する
todoList.appendChild(li);
}
}
// ToDo を保存する関数
function saveTodos() {
// 配列を JSON 文字列に変換して保存する
localStorage.setItem("todos", JSON.stringify(todos));
}
// 追加ボタンが押されたときの処理
addButton.addEventListener("click", function () {
// 入力内容を取得して前後の空白を除く
const text = todoInput.value.trim();
// 空欄なら追加しない
if (text === "") {
return;
}
// 新しい ToDo オブジェクトを配列に追加する
todos.push({
text: text,
completed: false
});
// localStorage に保存する
saveTodos();
// 画面を更新する
renderTodos();
// 入力欄を空にする
todoInput.value = "";
});
// ページ読み込み時に保存データを表示する
renderTodos();JavaScriptこのコードはDay 48の中心的な実践です。入力したToDoを配列へ追加し、その配列を丸ごと保存し、ページ読み込み時には保存データを配列へ戻して表示しています。
このコードの重要ポイントを深掘りする
この実践コードでは、初心者の方にぜひ理解してほしい大切な考え方がいくつかあります。
まず、todos という配列がアプリのデータの本体になっていることです。画面に表示されているリストが本体ではありません。本体はJavaScriptの配列であり、その配列を元にして画面を作っています。これは非常に重要です。初心者の方はつい、画面そのものがデータだと感じやすいですが、実際には「データを持っていて、そのデータをもとに画面を作っている」という構造です。
次に、saveTodos() と renderTodos() を分けていることも重要です。
- `saveTodos()` は保存だけを担当します。
- `renderTodos()` は表示だけを担当します。
この役割分担をしておくと、コードがかなり整理しやすくなります。初心者の方は、処理を1つの大きなかたまりにせず、「保存する処理」「表示する処理」のように分けて考えると学びやすいです。
ページ更新後も表示される仕組み
ここで改めて大事なのは、なぜページ更新後も表示されるのかということです。その理由は次の通りです。
- ToDoを追加したときに、配列を `localStorage` に保存しているからです。
- ページが開かれたときに、`localStorage` からその配列を取り出しているからです。
- 取り出した配列を `renderTodos()` で画面に表示しているからです。
つまり、「保存」「復元」「表示」の3つがつながっているからこそ実現できています。初心者の方は、この3段階をしっかり言葉で説明できるようになると、とても理解が深まります。
そのまま使える練習テンプレート
ここでは、学習しやすいようにコメントを多めにしたテンプレートを載せます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day 48 JSONとlocalStorage</title>
</head>
<body>
<h2>ToDoデータ保存アプリ</h2>
<input type="text" id="todoInput" placeholder="ToDoを入力してください">
<button id="addButton">追加</button>
<ul id="todoList"></ul>
<script>
// 必要な要素を取得する
const todoInput = document.getElementById("todoInput");
const addButton = document.getElementById("addButton");
const todoList = document.getElementById("todoList");
// localStorage から保存データを取得する
const savedTodos = localStorage.getItem("todos");
// 保存データがあれば JSON を配列に戻し、なければ空配列を使う
let todos = savedTodos !== null ? JSON.parse(savedTodos) : [];
// ToDo を localStorage に保存する関数
function saveTodos() {
localStorage.setItem("todos", JSON.stringify(todos));
}
// ToDo を画面に表示する関数
function renderTodos() {
// いったんリストを空にする
todoList.innerHTML = "";
// 配列の内容を1つずつ画面に表示する
for (const todo of todos) {
const li = document.createElement("li");
li.textContent = todo.text;
todoList.appendChild(li);
}
}
// 追加ボタンが押されたときの処理
addButton.addEventListener("click", function () {
// 入力内容を取得する
const text = todoInput.value.trim();
// 空欄なら追加しない
if (text === "") {
return;
}
// 新しい ToDo オブジェクトを追加する
todos.push({
text: text,
completed: false
});
// 保存する
saveTodos();
// 表示を更新する
renderTodos();
// 入力欄を空にする
todoInput.value = "";
});
// 初期表示として保存データを画面に出す
renderTodos();
</script>
</body>
</html>
このテンプレートをそのまま動かし、ToDoを追加してページを更新すると、保存されていることが確認できます。初心者の方は、まずここまでを確実に理解することが重要です。
初心者が特に注意したいポイント
Day 48では、次のポイントを特に意識すると理解が深まりやすいです。
- `localStorage` は文字列しか保存できません。
- 配列やオブジェクトを保存するには `JSON.stringify()` が必要です。
- 取り出したあと元の形に戻すには `JSON.parse()` が必要です。
- ToDo一覧全体は配列、1件ごとの情報はオブジェクトで持つと整理しやすいです。
- 保存処理と表示処理を分けるとコードが読みやすくなります。
特に重要なのは、「保存できるのは文字列だけ」という制約を正しく理解することです。この制約があるからこそJSONが必要であり、Day 48の学習内容が成り立っています。
セキュリティ面での注意
今回扱っているToDoやメモのような一般的なデータであれば、学習用として localStorage は使いやすいです。ただし、前日までと同じく、機密情報やパスワードのような重要データは保存しないことが大切です。localStorage は便利ですが、安全な秘密保管場所ではありません。
初心者の方は、「ToDoや表示設定のようなものには向いているが、重大な個人情報には向いていない」と覚えておくとよいです。
Day 48のゴールを整理する
Day 48では、次のことができるようになっていれば十分です。
- JSONが何のために必要か説明できる
- `JSON.stringify()` の役割を説明できる
- `JSON.parse()` の役割を説明できる
- 配列を `localStorage` に保存できる
- オブジェクトを `localStorage` に保存できる
- ToDoデータを配列とオブジェクトで表現できる
- 保存したToDoをページ更新後も表示できる
ここまでできれば、Day 48としてはとても順調です。単なる文字列保存から一歩進み、アプリらしいデータ構造を扱える段階に入っています。
まとめ
Day 48では、第4フェーズ「ブラウザデータ保存」を発展させて、JSONとlocalStorageを組み合わせる方法を学びました。今回の一番大切なポイントは、localStorage は文字列しか保存できないため、配列やオブジェクトを保存するには JSON.stringify() で文字列に変換し、取り出したあとに JSON.parse() で元の形へ戻す必要があるということです。この流れを理解することで、単純な1件の文字列保存だけでなく、複数データを持つ実用的なアプリにも対応できるようになります。
実践では、ToDo一覧全体を配列、ToDo1件ごとの情報をオブジェクトとして表現し、それを丸ごと保存・復元する方法を学びました。これは今後、完了状態の保存、削除状態の反映、複数項目の管理など、より本格的なToDoアプリへ発展させるための土台になります。特に重要なのは、「画面が本体ではなく、配列データが本体であり、そのデータをもとに画面を作っている」という考え方です。
次に進む前に、今回のテンプレートを何も見ずにもう一度作ってみるのがおすすめです。そして、そのあとで completed の情報も見た目に反映するように少し改造してみると、配列・オブジェクト・JSON・localStorage のつながりがさらに自然に理解できるようになります。
