基礎から学ぶJavaScript入門 90日コース | 最終制作 - Day 84:データ設計

JavaScript 90日で身につけるJavaScript
スポンサーリンク
スポンサーリンク

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: "引数と戻り値を復習"
});
JSON

crypto.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 "";
}
JSON

HTMLの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 [];
  }
}
JSON

localStorageにあるデータは、常に想定どおりの形とは限りません。古いバージョンのデータや、読み込みに失敗するデータがあることも考え、読み込んだ後に形式を確認します。保存容量や利用環境の制約もあるため、大量のデータを扱う用途には向きません。

ステップ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はサーバーや外部サービスとのデータのやり取りに使います。どちらを選ぶ場合も、必要なデータだけを扱い、入力値や読み込んだデータを確認し、秘密情報を不適切な場所に保存しないことが大切です。

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