Day 84:データ設計
Day 84では、アプリで扱うデータを決め、配列とオブジェクトの使い分け、localStorageやAPIの役割を整理します。画面を作ったあとにデータの形を考えるのではなく、「何を記録し、どう取り出し、どこに保存するか」を先に決めると、JavaScriptの処理を組み立てやすくなります。
ここでは、これまでの例に合わせて「学習管理アプリ」を題材にします。学習記録を追加・表示・削除し、合計時間を計算するアプリを想定します。
データ設計とは
データ設計とは、アプリが扱う情報の項目、データ型、まとまり方、保存場所を決めることです。たとえば「学習記録を保存する」といっても、学習内容だけでは一覧表示や合計時間の計算ができません。日付や学習時間など、必要な情報を整理する必要があります。
設計するときは、次の順に考えます。
- アプリの機能を実現するために必要な情報を書き出します。
- 1件分の情報を、どんな項目とデータ型で表すか決めます。
- 1件分のデータを複数まとめる方法を決めます。
- データを一時的に使うのか、あとで使えるよう保存するのか決めます。
- 保存先として`localStorage`やAPIなど、目的に合う方法を選びます。
ステップ1:必要なデータを洗い出す
学習管理アプリの機能を見ながら、必要なデータを考えます。記録の追加、一覧表示、削除、合計時間の表示には、次の項目があると便利です。
- `id`:記録を区別するための値です。
- `title`:学習した内容です。
- `minutes`:学習時間を分で表した数値です。
- `date`:学習した日付です。
- `note`:補足メモです。入力を任意にできます。
- `createdAt`:記録を作成した日時です。並び替えなどに利用できます。
各項目が必要かどうかは、アプリの機能によって決まります。使わない情報まで保存すると、管理が複雑になります。まずは最初の完成版に必要な項目だけに絞りましょう。
ステップ2:データ型を決める
項目ごとに、文字列、数値、真偽値などのデータ型を決めます。たとえば、学習時間を"45分"という文字列で保存すると、合計を計算するときに文字列から数値を取り出す必要があります。45という数値で保存すれば、足し算しやすくなります。
| 項目 | データ型の例 | 理由 |
|---|---|---|
| `id` | 文字列 | 記録を識別するため |
| `title` | 文字列 | 学習内容を表すため |
| `minutes` | 数値 | 合計や比較に使うため |
| `date` | 文字列 | `YYYY-MM-DD`形式で日付を扱うため |
| `note` | 文字列 | 任意のメモを保存するため |
| `createdAt` | 文字列 | 日時をISO形式で保存するため |
日付を文字列で持つ場合は、保存形式を統一します。たとえば2026-11-10のように年・月・日の順にすると、比較や並べ替えがしやすくなります。
ステップ3:1件分はオブジェクトで表す
関連する複数の値をひとまとまりにするには、オブジェクトを使います。学習記録1件分を次のように表せます。
// 学習記録1件分のデータ例
const studyRecord = {
id: "record-001", // 記録を識別するID
title: "JavaScriptの配列", // 学習した内容
minutes: 40, // 学習時間(分)
date: "2026-11-10", // 学習した日付
note: "mapとfilterを復習しました。", // 補足メモ
createdAt: "2026-11-10T09:30:00.000Z" // 作成日時
};JSONオブジェクトにすると、「この記録の学習内容」や「この記録の時間」を、studyRecord.title、studyRecord.minutesのように取り出せます。データの意味がわかりやすく、機能を追加するときにも扱いやすくなります。
ステップ4:複数件は配列でまとめる
学習記録は1件だけではなく、複数件を保存します。同じ形のオブジェクトをまとめるには、配列を使います。
// 学習記録を複数件まとめた配列
const studyRecords = [
{
id: "record-001", // 1件目のID
title: "JavaScriptの配列", // 1件目の学習内容
minutes: 40, // 1件目の学習時間
date: "2026-11-10", // 1件目の日付
note: "mapとfilterを復習", // 1件目のメモ
createdAt: "2026-11-10T09:30:00.000Z" // 1件目の作成日時
},
{
id: "record-002", // 2件目のID
title: "関数の復習", // 2件目の学習内容
minutes: 30, // 2件目の学習時間
date: "2026-11-09", // 2件目の日付
note: "", // メモがない場合は空文字にする
createdAt: "2026-11-09T11:00:00.000Z" // 2件目の作成日時
}
];JSONこの設計では、1件分をオブジェクト、複数件を配列で表しています。配列にすることで、一覧表示、検索、削除、合計時間の計算ができます。
ステップ5:データの形をテンプレートにする
アプリ内で記録を追加するときに毎回同じ項目を用意できるよう、データの形をテンプレートとして考えます。新しい記録を作る関数の例です。
// 入力値から新しい学習記録を作る
function createStudyRecord({ title, minutes, date, note = "" }) {
return {
id: crypto.randomUUID(), // 新しい記録に一意のIDを付ける
title: title.trim(), // 前後の空白を除いて保存する
minutes: Number(minutes), // 学習時間を数値にする
date, // 学習した日付を保存する
note: note.trim(), // メモの前後の空白を除く
createdAt: new Date().toISOString() // 作成日時を保存する
};
}
// 入力値から記録を1件作る
const newRecord = createStudyRecord({
title: "JavaScriptの関数",
minutes: 35,
date: "2026-11-10",
note: "引数と戻り値を復習"
});JSONcrypto.randomUUID()は、一意のIDを作るために利用できる機能です。利用環境によっては使えない場合もあるため、実際のアプリでは対象ブラウザーを確認してください。初心者向けの設計では、「各記録に他と重なりにくいIDを持たせる」という考え方をまず押さえましょう。
ステップ6:入力値のルールを決める
画面から受け取った値を、そのまま保存するのではなく、保存前にルールを確認します。学習管理アプリなら、次のような条件が考えられます。
- 学習内容は空欄ではないこと。
- 学習時間は数値で、0より大きいこと。
- 日付は入力されていること。
- メモは空でもよいこと。
入力確認を行う関数の例です。
// 学習記録の入力値を確認する
function validateStudyRecord({ title, minutes, date }) {
if (typeof title !== "string" || title.trim() === "") {
return "学習内容を入力してください。";
}
const numericMinutes = Number(minutes);
if (!Number.isFinite(numericMinutes) || numericMinutes <= 0) {
return "学習時間には0より大きい数値を入力してください。";
}
if (typeof date !== "string" || date === "") {
return "学習日を入力してください。";
}
// 問題がなければエラーメッセージなしを返す
return "";
}JSONHTMLのrequiredやminなどは入力時の助けになりますが、アプリのデータとして正しいか確認する処理も必要です。データ設計では、項目だけでなく「どんな値を受け付けるか」まで決めておきましょう。
ステップ7:localStorageを使うか考える
localStorageは、ブラウザー内に文字列データを保存する仕組みです。サーバーを用意しなくても扱えるため、学習用アプリでデータを保存する方法として便利です。
- ページを再読み込みしても、同じブラウザー内にデータを残せます。
- JavaScriptの配列やオブジェクトは、JSON文字列へ変換して保存します。
- 基本的に、保存したブラウザーや端末をまたいで自動同期はされません。
- パスワードやAPIキーなどの秘密情報を保存する場所には適しません。
localStorageは文字列を保存するため、保存前にJSON.stringify()、読み込み時にJSON.parse()を使います。
const STORAGE_KEY = "studyRecords";
// 学習記録の配列をブラウザーに保存する
function saveStudyRecords(records) {
// 配列をJSON文字列に変換して保存する
localStorage.setItem(STORAGE_KEY, JSON.stringify(records));
}
// ブラウザーから学習記録を読み込む
function loadStudyRecords() {
const savedText = localStorage.getItem(STORAGE_KEY);
// 保存データがまだなければ、空の配列を返す
if (savedText === null) {
return [];
}
try {
// JSON文字列をJavaScriptの値に戻す
const parsedData = JSON.parse(savedText);
// 配列以外のデータが保存されていた場合は、安全のため空配列にする
if (!Array.isArray(parsedData)) {
return [];
}
return parsedData;
} catch (error) {
// 壊れたJSONなどで読み込みに失敗した場合の処理
console.error("学習記録を読み込めませんでした。", error);
return [];
}
}JSONlocalStorageにあるデータは、常に想定どおりの形とは限りません。古いバージョンのデータや、読み込みに失敗するデータがあることも考え、読み込んだ後に形式を確認します。保存容量や利用環境の制約もあるため、大量のデータを扱う用途には向きません。
ステップ8:APIを使うか考える
APIは、アプリと外部のサーバーとの間でデータをやり取りするための窓口です。映画検索やレシピ検索のように、外部のサービスが持つデータを取得するときに使います。
localStorageとAPIは、同じ役割ではありません。
| 方法 | 主な役割 | 向いている例 |
|---|---|---|
| `localStorage` | 利用中のブラウザーにデータを保存する | 学習記録や設定を同じ端末で使う |
| API | サーバーとデータを送受信する | 映画情報やレシピ情報を検索する |
たとえば、学習管理アプリの記録を自分のブラウザーだけで使うなら、最初の版ではlocalStorageで十分な場合があります。一方、映画検索アプリのように外部サービスの映画情報を表示するなら、APIを使う設計が必要です。
APIを使う場合は、次の点も設計に含めます。
- 読み込み中に何を表示するか。
- 検索結果が0件のときに何を表示するか。
- 通信に失敗したとき、利用者にどう案内するか。
- APIキーが必要な場合、どのように安全に管理するか。
- サービスの利用条件やリクエスト制限をどう守るか。
APIキーをブラウザーで動くJavaScriptへ直接書くと、利用者から見える可能性があります。公開してはいけないキーは、フロントエンドのコードへ埋め込まず、サービスの推奨する安全な管理方法を確認してください。
ステップ9:保存方法を選ぶ
どの保存方法を選ぶかは、アプリの目的によります。
- 同じブラウザー内で自分の記録を使えればよい:`localStorage`を検討します。
- 外部サービスの情報を取得したい:APIを検討します。
- 複数端末で同じアカウントのデータを使いたい:サーバー側の保存機能が必要です。
- パスワードや重要な個人情報を扱いたい:保存場所や認証を含め、追加の安全設計が必要です。
最初の制作では、必要のないサーバー機能まで作ろうとせず、アプリの目的を満たす一番小さな保存方法を選びます。あとから必要になったときに、データ構造を見直して拡張できます。
ステップ10:画面とデータを対応させる
データ項目が決まったら、画面の入力欄や表示場所と対応させます。
- 学習内容の入力欄 → `title`
- 学習時間の入力欄 → `minutes`
- 学習日の入力欄 → `date`
- メモの入力欄 → `note`
- 学習履歴の各項目 → 記録オブジェクト1件分
- 合計時間の表示 → 各記録の`minutes`を合計した値
合計時間は保存しておく方法もありますが、記録の追加や削除のたびに合計も更新しなければならず、値がずれる可能性があります。最初の版では、記録配列から合計を計算する設計がシンプルです。
// 学習記録の配列から合計時間を計算する
function calculateTotalMinutes(records) {
return records.reduce(function (total, record) {
return total + record.minutes;
}, 0);
}
// 合計時間を確認する
const totalMinutes = calculateTotalMinutes(studyRecords);
console.log(`合計学習時間:${totalMinutes}分`);JSONデータ設計のテンプレート
最終制作のデータ項目を整理するときは、次のテンプレートを使えます。
データ名:
何のために使うか:
項目:
- 名前:
データ型:
必須か:
入力ルール:
画面のどこで使うか:
1件分を表す方法:
複数件をまとめる方法:
保存方法:
- localStorage / API / その他
読み込み時に確認すること:
入力エラー時の扱い:
秘密情報や個人情報の扱い:
Day 84のゴール
Day 84では、次のことができるようになっていれば十分です。
- アプリに必要なデータ項目を書き出せます。
- 1件分をオブジェクト、複数件を配列で表せます。
- 各項目のデータ型と入力ルールを決められます。
- `localStorage`とAPIの役割の違いを説明できます。
- アプリの目的に合った保存方法を選べます。
- 読み込みエラーや秘密情報の扱いも考慮できます。
まとめ
Day 84では、学習管理アプリを例に、必要なデータ、配列とオブジェクトの使い分け、localStorageとAPIの選び方を整理しました。1件分の記録をオブジェクトで表し、同じ形の記録を配列にまとめると、追加、一覧表示、削除、合計計算を組み立てやすくなります。
localStorageは同じブラウザー内にデータを残す用途に向き、APIはサーバーや外部サービスとのデータのやり取りに使います。どちらを選ぶ場合も、必要なデータだけを扱い、入力値や読み込んだデータを確認し、秘密情報を不適切な場所に保存しないことが大切です。
