基礎から学ぶJavaScript入門 90日コース | JavaScriptでデータを扱う - Day 28:データ処理演習②

90日で身につけるJavaScript
スポンサーリンク
スポンサーリンク
  1. Day 28:データ処理演習②(前半)
  2. ユーザーデータの準備:オブジェクトの配列で表現する
    1. ユーザー1人をオブジェクトで表す
    2. 複数ユーザーを配列でまとめる
  3. ユーザー一覧表示:基本の“見る”機能
    1. 1人のユーザーを表示する関数
    2. ユーザー一覧を表示する関数
  4. ユーザー検索:名前で探す
    1. 検索条件を決める
    2. 検索関数を作る
    3. 検索結果を表示する関数
  5. 年齢フィルター:条件で絞り込む
    1. フィルター条件を決める
    2. 年齢フィルター関数を作る
    3. フィルター結果を表示する関数
  6. ソート:年齢順に並び替える
    1. ソートの基本:Array.prototype.sort()
    2. 年齢で昇順ソートする関数
    3. ソート結果を表示する関数
  7. データ追加:新しいユーザーを配列に加える
    1. 「追加」の基本:push() を使う
    2. ユーザー追加関数を作る
    3. 新しいユーザーを作って追加する
  8. Day 28 前半 練習テンプレート(ブラウザで実行可能)
  9. Day 28 前半のまとめ
  10. Day 28:データ処理演習②(後半)
  11. ユーザーデータの土台を再確認する
  12. ユーザー検索:入力チェックと“柔らかい検索”
    1. ステップ1:検索関数を“防御的”にする
    2. ステップ2:検索結果表示を“ユーザー目線”にする
  13. 年齢フィルター:境界値と不正値を意識する
    1. ステップ1:フィルター関数を“堅牢”にする
    2. ステップ2:フィルター結果表示を“わかりやすく”する
  14. ソート:元データを壊さず、柔軟な並び替えをする
    1. ステップ1:昇順・降順を切り替えられるソート関数
    2. ステップ2:ソート結果表示を分かりやすくする
  15. データ追加:最低限のバリデーションを意識する
    1. ステップ1:追加前に“ざっくりチェック”する
    2. ステップ2:追加関数でバリデーションを使う
    3. ステップ3:追加前後の状態を確認する
  16. Day 28 後半 練習テンプレート(ブラウザで実行可能)
  17. Day 28 後半のまとめ

Day 28:データ処理演習②(前半)

「ユーザーデータを“整理して扱う”力を鍛える」

Day 28では、ユーザーデータを題材にして、

  • ユーザー検索
  • 年齢フィルター
  • ソート(並び替え)
  • データ追加

をまとめて練習していきます。 商品データと同じく「オブジェクトの配列」を使いますが、 今回は ユーザーという“人”を表すデータ を扱うことで、 より実務に近い感覚を育てていきます。

ユーザーデータの準備:オブジェクトの配列で表現する

ユーザー1人をオブジェクトで表す

まずは、ユーザー1人をオブジェクトで表現します。

// 1人のユーザーの例
const user = {
  id: 1,
  name: '佐藤太郎',
  age: 28,
  email: 'taro.sato@example.com',
};
JavaScript
  • id:ユーザーを一意に識別する番号
  • name:名前
  • age:年齢
  • email:メールアドレス

複数ユーザーを配列でまとめる

これを複数人分まとめて、配列にします。

// ユーザーデータの配列
const users = [
  { id: 1, name: '佐藤太郎',   age: 28, email: 'taro.sato@example.com' },
  { id: 2, name: '鈴木花子',   age: 34, email: 'hanako.suzuki@example.com' },
  { id: 3, name: '高橋健',     age: 22, email: 'ken.takahashi@example.com' },
  { id: 4, name: '田中美咲',   age: 19, email: 'misaki.tanaka@example.com' },
  { id: 5, name: '伊藤翔',     age: 41, email: 'sho.ito@example.com' },
];
JavaScript

この配列が、 「ユーザーデータベースのようなもの」 だと考えてください。

ユーザー一覧表示:基本の“見る”機能

1人のユーザーを表示する関数

まずは、1人のユーザーを見やすく表示する関数を作ります。

// 1人のユーザーを表示する関数
function printUser(user) {
  console.log(`ID: ${user.id}/名前: ${user.name}/年齢: ${user.age}歳/メール: ${user.email}`);
}
JavaScript

ユーザー一覧を表示する関数

次に、配列 users を受け取って、 全員を表示する関数を作ります。

// ユーザー一覧を表示する関数
function printUserList(users) {
  console.log('--- ユーザー一覧 ---');

  for (const user of users) {
    printUser(user);
  }

  console.log('--- ユーザー一覧ここまで ---');
}

// 実行例
printUserList(users);
JavaScript
  • 商品一覧と同じく、配列をループして1件ずつ表示する パターンです。
  • この一覧表示関数は、後で「検索結果」「フィルター結果」「ソート結果」を表示するときにも使い回します。

ユーザー検索:名前で探す

検索条件を決める

ここでは、 「名前に特定の文字列が含まれているユーザーを探す」 という検索を作ります。

例:

  • 「佐藤」で検索 → 「佐藤太郎」がヒット
  • 「田中」で検索 → 「田中美咲」がヒット

検索関数を作る

// 名前にキーワードが含まれているユーザーを検索する関数
function searchUsersByName(users, keyword) {
  const result = [];

  for (const user of users) {
    // 名前にキーワードが含まれているかを判定します
    if (user.name.includes(keyword)) {
      result.push(user); // 条件に合うユーザーを結果配列に追加
    }
  }

  return result;
}
JavaScript

検索結果を表示する関数

検索結果が0件のときのメッセージも含めて、 表示用の関数を作ります。

function printSearchUsers(users, keyword) {
  const result = searchUsersByName(users, keyword);

  console.log(`--- ユーザー検索(キーワード: "${keyword}") ---`);

  if (result.length === 0) {
    console.log('該当するユーザーは見つかりませんでした。');
  } else {
    printUserList(result);
  }

  console.log('--- ユーザー検索ここまで ---');
}

// 実行例
printSearchUsers(users, '佐藤');   // ヒットあり
printSearchUsers(users, '田中');   // ヒットあり
printSearchUsers(users, '山本');   // ヒットなし
JavaScript
  • 「検索」は、条件に合うものだけを新しい配列に集める パターンです。
  • 0件のときのメッセージを用意しておくと、ツールとして親切になります。

年齢フィルター:条件で絞り込む

フィルター条件を決める

ここでは、 「指定した年齢以上のユーザーだけを抽出する」 というフィルターを作ります。

例:

  • 30歳以上 → 鈴木花子(34)、伊藤翔(41)

年齢フィルター関数を作る

// 指定年齢以上のユーザーだけを抽出する関数
function filterUsersByMinAge(users, minAge) {
  const result = [];

  for (const user of users) {
    if (user.age >= minAge) {
      result.push(user);
    }
  }

  return result;
}
JavaScript

フィルター結果を表示する関数

入力値のチェックも軽く入れておきます。

function printFilteredUsersByMinAge(users, minAge) {
  console.log(`--- 年齢フィルター(${minAge}歳以上) ---`);

  // minAgeが数値かどうかをチェックします
  if (typeof minAge !== 'number' || Number.isNaN(minAge) || minAge < 0) {
    console.log('年齢の指定が不正です。0以上の数値を指定してください。');
    console.log('--- 表示を中止します ---');
    return;
  }

  const result = filterUsersByMinAge(users, minAge);

  if (result.length === 0) {
    console.log('該当するユーザーは見つかりませんでした。');
  } else {
    printUserList(result);
  }

  console.log('--- 年齢フィルターここまで ---');
}

// 実行例
printFilteredUsersByMinAge(users, 30);   // 正常
printFilteredUsersByMinAge(users, -10);  // 不正値
JavaScript
  • 「年齢フィルター」は、商品データの「価格フィルター」と同じパターンです。
  • 不正な入力に対してメッセージを出すことで、ツールとしての安全性が上がります。

ソート:年齢順に並び替える

ソートの基本:Array.prototype.sort()

JavaScriptの配列には、 sort() メソッド が用意されています。

const numbers = [3, 1, 5, 2];
numbers.sort(); // [1, 2, 3, 5]
JavaScript

しかし、オブジェクトの配列をソートするときは、 「どのプロパティを基準にするか」を自分で指定する必要があります。

年齢で昇順ソートする関数

// ユーザー配列を年齢の昇順(若い順)に並び替える関数
function sortUsersByAgeAsc(users) {
  // 元の配列を壊さないように、コピーを作ります
  const copied = [...users];

  copied.sort((a, b) => {
    return a.age - b.age; // 年齢が小さい順に並ぶ
  });

  return copied;
}
JavaScript
  • sort() に渡している関数は「比較関数」と呼ばれます。
  • a.age - b.age が負なら a が先、正なら b が先、0なら同じ位置というルールです。
  • 元の配列を直接ソートするとデータが書き換わってしまうので、 スプレッド構文 [...] でコピーを作ってからソートしています。

ソート結果を表示する関数

function printSortedUsersByAgeAsc(users) {
  console.log('--- 年齢昇順ソート(若い順) ---');

  const sorted = sortUsersByAgeAsc(users);
  printUserList(sorted);

  console.log('--- 年齢昇順ソートここまで ---');
}

// 実行例
printSortedUsersByAgeAsc(users);
JavaScript
  • ソートは、「同じデータを別の順番で見る」 ための機能です。
  • 実務では「登録日順」「名前順」「スコア順」など、 さまざまなソートが頻繁に使われます。

データ追加:新しいユーザーを配列に加える

「追加」の基本:push() を使う

配列に新しい要素を追加するには、 push() メソッド を使います。

const arr = [1, 2];
arr.push(3); // [1, 2, 3]
JavaScript

これをユーザーデータに対して使います。

ユーザー追加関数を作る

// 新しいユーザーを追加する関数
function addUser(users, newUser) {
  users.push(newUser); // 配列の末尾に追加
}
JavaScript

新しいユーザーを作って追加する

const newUser = {
  id: 6,
  name: '山本優',
  age: 25,
  email: 'yu.yamamoto@example.com',
};

console.log('--- ユーザー追加前の一覧 ---');
printUserList(users);

addUser(users, newUser);

console.log('--- ユーザー追加後の一覧 ---');
printUserList(users);
JavaScript
  • ここではシンプルに push() で追加しています。
  • 実務では「idが重複していないか」「メールアドレスが妥当か」などのチェックも必要になりますが、 Day 28前半では「配列に新しいオブジェクトを追加する」という基本動作に集中します。

Day 28 前半 練習テンプレート(ブラウザで実行可能)

以下のテンプレートをブラウザで開き、 コンソールで「ユーザー一覧」「検索」「年齢フィルター」「ソート」「追加」を確認してください。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 28 前半:データ処理演習② テンプレート</title>
</head>
<body>
  <h1>Day 28 前半:ユーザーデータ処理演習②</h1>
  <p>ブラウザのコンソールを開いて、ログを確認してください。</p>

  <script>
    console.log('--- ユーザーデータの準備 ---');

    const users = [
      { id: 1, name: '佐藤太郎',   age: 28, email: 'taro.sato@example.com' },
      { id: 2, name: '鈴木花子',   age: 34, email: 'hanako.suzuki@example.com' },
      { id: 3, name: '高橋健',     age: 22, email: 'ken.takahashi@example.com' },
      { id: 4, name: '田中美咲',   age: 19, email: 'misaki.tanaka@example.com' },
      { id: 5, name: '伊藤翔',     age: 41, email: 'sho.ito@example.com' },
    ];

    function printUser(user) {
      console.log(`ID: ${user.id}/名前: ${user.name}/年齢: ${user.age}歳/メール: ${user.email}`);
    }

    function printUserList(users) {
      console.log('--- ユーザー一覧 ---');
      for (const user of users) {
        printUser(user);
      }
      console.log('--- ユーザー一覧ここまで ---');
    }

    console.log('--- ユーザー一覧を表示 ---');
    printUserList(users);

    console.log('--- ユーザー検索(名前で部分一致) ---');

    function searchUsersByName(users, keyword) {
      const result = [];

      for (const user of users) {
        if (user.name.includes(keyword)) {
          result.push(user);
        }
      }

      return result;
    }

    function printSearchUsers(users, keyword) {
      const result = searchUsersByName(users, keyword);

      console.log(`--- ユーザー検索(キーワード: "${keyword}") ---`);

      if (result.length === 0) {
        console.log('該当するユーザーは見つかりませんでした。');
      } else {
        printUserList(result);
      }

      console.log('--- ユーザー検索ここまで ---');
    }

    printSearchUsers(users, '佐藤');
    printSearchUsers(users, '山本');

    console.log('--- 年齢フィルター(指定年齢以上) ---');

    function filterUsersByMinAge(users, minAge) {
      const result = [];

      for (const user of users) {
        if (user.age >= minAge) {
          result.push(user);
        }
      }

      return result;
    }

    function printFilteredUsersByMinAge(users, minAge) {
      console.log(`--- 年齢フィルター(${minAge}歳以上) ---`);

      if (typeof minAge !== 'number' || Number.isNaN(minAge) || minAge < 0) {
        console.log('年齢の指定が不正です。0以上の数値を指定してください。');
        console.log('--- 表示を中止します ---');
        return;
      }

      const result = filterUsersByMinAge(users, minAge);

      if (result.length === 0) {
        console.log('該当するユーザーは見つかりませんでした。');
      } else {
        printUserList(result);
      }

      console.log('--- 年齢フィルターここまで ---');
    }

    printFilteredUsersByMinAge(users, 30);
    printFilteredUsersByMinAge(users, -10);

    console.log('--- 年齢昇順ソート(若い順) ---');

    function sortUsersByAgeAsc(users) {
      const copied = [...users];

      copied.sort((a, b) => {
        return a.age - b.age;
      });

      return copied;
    }

    function printSortedUsersByAgeAsc(users) {
      console.log('--- 年齢昇順ソート(若い順) ---');
      const sorted = sortUsersByAgeAsc(users);
      printUserList(sorted);
      console.log('--- 年齢昇順ソートここまで ---');
    }

    printSortedUsersByAgeAsc(users);

    console.log('--- ユーザー追加 ---');

    function addUser(users, newUser) {
      users.push(newUser);
    }

    const newUser = {
      id: 6,
      name: '山本優',
      age: 25,
      email: 'yu.yamamoto@example.com',
    };

    console.log('ユーザー追加前:');
    printUserList(users);

    addUser(users, newUser);

    console.log('ユーザー追加後:');
    printUserList(users);

    console.log('--- Day 28 前半:データ処理演習②の練習が完了しました ---');
  </script>
</body>
</html>

Day 28 前半のまとめ

Day 28前半では、

  • ユーザーデータを「オブジェクトの配列」で表現する基本形
  • 名前検索・年齢フィルターで「条件に合うユーザーだけを取り出す」パターン
  • sort() を使って「年齢順に並び替える」ソート処理
  • push() を使って「新しいユーザーを配列に追加する」基本動作

を確認しました。

ユーザーデータは、 実務でも非常に頻繁に扱われる題材です。

Day 28後半では、 これらの処理をさらに発展させて、 「安全性」「再利用性」「現実的なユースケース」を意識した データ処理演習へと進んでいきます。


Day 28:データ処理演習②(後半)

「“雑なコード”から“信頼できるコード”へ育てていく」

Day 28後半では、前半で作った

  • ユーザー検索
  • 年齢フィルター
  • ソート
  • データ追加

を、もう一歩「実務で使える」レベルに近づけていきます。 ここでは、

  • 入力値のチェック(バリデーション)
  • 元データを壊さない工夫
  • エラーや想定外のケースへの備え
  • セキュリティの視点(最低限の意識)

を加えながら、同じ機能を“質の高いコード”に育てていきます。

ユーザーデータの土台を再確認する

まずは、前半と同じユーザーデータを使います。

// ユーザーデータの配列(1件が1人のユーザー)
const users = [
  { id: 1, name: '佐藤太郎',   age: 28, email: 'taro.sato@example.com' },
  { id: 2, name: '鈴木花子',   age: 34, email: 'hanako.suzuki@example.com' },
  { id: 3, name: '高橋健',     age: 22, email: 'ken.takahashi@example.com' },
  { id: 4, name: '田中美咲',   age: 19, email: 'misaki.tanaka@example.com' },
  { id: 5, name: '伊藤翔',     age: 41, email: 'sho.ito@example.com' },
];
JavaScript

一覧表示用の関数もそのまま使います。

// 1人のユーザーを表示する関数
function printUser(user) {
  console.log(`ID: ${user.id}/名前: ${user.name}/年齢: ${user.age}歳/メール: ${user.email}`);
}

// ユーザー一覧を表示する関数
function printUserList(users) {
  console.log('--- ユーザー一覧 ---');
  for (const user of users) {
    printUser(user);
  }
  console.log('--- ユーザー一覧ここまで ---');
}
JavaScript

この土台の上に、「より安全で再利用しやすい機能」を積み上げていきます。

ユーザー検索:入力チェックと“柔らかい検索”

ステップ1:検索関数を“防御的”にする

前半の検索関数は、キーワードが空文字でもそのまま動いていました。 後半では、次のような点を意識して改善します。

  • キーワードが空文字や空白だけの場合は「検索しない」
  • 大文字・小文字の違いを気にせず検索できるようにする(柔らかい検索)
// 名前にキーワードが含まれているユーザーを検索する関数(改善版)
function searchUsersByNameSafe(users, keyword) {
  // 入力チェック:nullやundefinedを防ぐ
  if (typeof keyword !== 'string') {
    return [];
  }

  // 前後の空白を削除
  const trimmed = keyword.trim();

  // 空文字なら検索しない(結果は0件)
  if (trimmed === '') {
    return [];
  }

  // 大文字・小文字を区別しない検索のために、両方を小文字にします
  const lowerKeyword = trimmed.toLowerCase();

  const result = [];

  for (const user of users) {
    const lowerName = user.name.toLowerCase();

    if (lowerName.includes(lowerKeyword)) {
      result.push(user);
    }
  }

  return result;
}
JavaScript

ステップ2:検索結果表示を“ユーザー目線”にする

function printSearchUsersSafe(users, keyword) {
  console.log(`--- ユーザー検索(キーワード: "${keyword}") ---`);

  const result = searchUsersByNameSafe(users, keyword);

  if (result.length === 0) {
    console.log('該当するユーザーは見つかりませんでした。');
    console.log('キーワードを変えて再度お試しください。');
  } else {
    printUserList(result);
  }

  console.log('--- ユーザー検索ここまで ---');
}

// 実行例
printSearchUsersSafe(users, '佐藤');
printSearchUsersSafe(users, '  花子  '); // 前後に空白があっても検索
printSearchUsersSafe(users, '');         // 空文字 → 0件
printSearchUsersSafe(users, 123);        // 不正型 → 0件
JavaScript
  • 入力チェックを入れることで、「おかしな値」が来ても安全に動作します。
  • 大文字・小文字を区別しない検索は、実務でもよく使われる“優しい検索”のパターンです。

年齢フィルター:境界値と不正値を意識する

ステップ1:フィルター関数を“堅牢”にする

前半の filterUsersByMinAge を、 次の点を意識して改善します。

  • 年齢が数値でないユーザーが混ざっていても落ちないようにする
  • minAge が不正な値でも安全に動作する
// 指定年齢以上のユーザーだけを抽出する関数(改善版)
function filterUsersByMinAgeSafe(users, minAge) {
  // minAgeの入力チェック
  if (typeof minAge !== 'number' || Number.isNaN(minAge) || minAge < 0) {
    return [];
  }

  const result = [];

  for (const user of users) {
    // user.ageが数値かどうかを確認します
    if (typeof user.age !== 'number' || Number.isNaN(user.age)) {
      // 年齢情報が不正なユーザーはスキップします
      continue;
    }

    if (user.age >= minAge) {
      result.push(user);
    }
  }

  return result;
}
JavaScript

ステップ2:フィルター結果表示を“わかりやすく”する

function printFilteredUsersByMinAgeSafe(users, minAge) {
  console.log(`--- 年齢フィルター(${minAge}歳以上) ---`);

  const result = filterUsersByMinAgeSafe(users, minAge);

  if (result.length === 0) {
    console.log('条件に合うユーザーは見つかりませんでした。');
    console.log('年齢の条件やデータを確認してください。');
  } else {
    printUserList(result);
  }

  console.log('--- 年齢フィルターここまで ---');
}

// 実行例
printFilteredUsersByMinAgeSafe(users, 30);
printFilteredUsersByMinAgeSafe(users, -10); // 不正値 → 0件
printFilteredUsersByMinAgeSafe(users, '30'); // 不正型 → 0件
JavaScript
  • 「不正な入力が来たときにどうするか」を決めておくことで、 予期しないクラッシュを防げます。
  • 年齢情報が壊れているユーザーが混ざっていても、 スキップすることで全体の処理は継続できます。

ソート:元データを壊さず、柔軟な並び替えをする

ステップ1:昇順・降順を切り替えられるソート関数

前半では「年齢昇順(若い順)」だけでしたが、 後半では「昇順・降順を切り替えられる」関数にします。

// ユーザー配列を年齢でソートする関数(昇順・降順対応)
function sortUsersByAge(users, order = 'asc') {
  // 元の配列を壊さないようにコピーを作ります
  const copied = [...users];

  copied.sort((a, b) => {
    // 年齢が数値でない場合の安全策
    const ageA = (typeof a.age === 'number' && !Number.isNaN(a.age)) ? a.age : 0;
    const ageB = (typeof b.age === 'number' && !Number.isNaN(b.age)) ? b.age : 0;

    if (order === 'asc') {
      // 昇順(若い順)
      return ageA - ageB;
    } else if (order === 'desc') {
      // 降順(年上順)
      return ageB - ageA;
    } else {
      // 不正なorderが来た場合は昇順にしておく
      return ageA - ageB;
    }
  });

  return copied;
}
JavaScript

ステップ2:ソート結果表示を分かりやすくする

function printSortedUsersByAge(users, order) {
  const label = order === 'desc' ? '年齢降順ソート(年上順)' : '年齢昇順ソート(若い順)';

  console.log(`--- ${label} ---`);

  const sorted = sortUsersByAge(users, order);
  printUserList(sorted);

  console.log(`--- ${label}ここまで ---`);
}

// 実行例
printSortedUsersByAge(users, 'asc');  // 若い順
printSortedUsersByAge(users, 'desc'); // 年上順
printSortedUsersByAge(users, 'xxx');  // 不正値 → 昇順扱い
JavaScript
  • ソートは「元データを壊さない」ことが非常に重要です。
  • スプレッド構文でコピーを作ってからソートすることで、 元の users 配列はそのまま保たれます。

データ追加:最低限のバリデーションを意識する

ステップ1:追加前に“ざっくりチェック”する

ユーザー追加は、 実務ではセキュリティや整合性の観点から慎重に扱う必要があります。

ここでは、最低限として次のチェックを入れます。

  • id が数値であること
  • name が空文字でないこと
  • age が0以上の数値であること
  • email が空文字でないこと
// 新しいユーザーが妥当かどうかをざっくりチェックする関数
function validateNewUser(newUser) {
  if (typeof newUser.id !== 'number' || Number.isNaN(newUser.id)) {
    return { valid: false, message: 'IDが不正です。数値を指定してください。' };
  }

  if (typeof newUser.name !== 'string' || newUser.name.trim() === '') {
    return { valid: false, message: '名前が不正です。空でない文字列を指定してください。' };
  }

  if (typeof newUser.age !== 'number' || Number.isNaN(newUser.age) || newUser.age < 0) {
    return { valid: false, message: '年齢が不正です。0以上の数値を指定してください。' };
  }

  if (typeof newUser.email !== 'string' || newUser.email.trim() === '') {
    return { valid: false, message: 'メールアドレスが不正です。空でない文字列を指定してください。' };
  }

  // ここでは簡略化のため、メールアドレスの形式チェックは省略します
  return { valid: true, message: 'OK' };
}
JavaScript

ステップ2:追加関数でバリデーションを使う

// 新しいユーザーを追加する関数(バリデーション付き)
function addUserSafe(users, newUser) {
  const result = validateNewUser(newUser);

  if (!result.valid) {
    console.log('ユーザー追加に失敗しました:' + result.message);
    return false; // 追加失敗
  }

  // IDの重複チェック(簡易版)
  const exists = users.some(user => user.id === newUser.id);
  if (exists) {
    console.log('ユーザー追加に失敗しました:同じIDのユーザーが既に存在します。');
    return false;
  }

  users.push(newUser);
  console.log('ユーザーを追加しました:', newUser);
  return true; // 追加成功
}
JavaScript

ステップ3:追加前後の状態を確認する

console.log('--- ユーザー追加テスト ---');

const validUser = {
  id: 6,
  name: '山本優',
  age: 25,
  email: 'yu.yamamoto@example.com',
};

const invalidUser = {
  id: 'abc', // 不正なID
  name: '',
  age: -10,
  email: '',
};

console.log('追加前:');
printUserList(users);

console.log('妥当なユーザーを追加します');
addUserSafe(users, validUser);

console.log('不正なユーザーを追加しようとします');
addUserSafe(users, invalidUser);

console.log('追加後:');
printUserList(users);
JavaScript
  • バリデーションを入れることで、「明らかにおかしいデータ」が入るのを防げます。
  • IDの重複チェックは、実務では必須に近い考え方です。

Day 28 後半 練習テンプレート(ブラウザで実行可能)

以下のテンプレートをブラウザで開き、 コンソールで「安全な検索・フィルター・ソート・追加」の動きを確認してください。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 28 後半:データ処理演習② 練習テンプレート</title>
</head>
<body>
  <h1>Day 28 後半:ユーザーデータ処理演習②(安全性と再利用性を意識した版)</h1>
  <p>ブラウザのコンソールを開いて、ログを確認してください。</p>

  <script>
    console.log('--- ユーザーデータの準備 ---');

    const users = [
      { id: 1, name: '佐藤太郎',   age: 28, email: 'taro.sato@example.com' },
      { id: 2, name: '鈴木花子',   age: 34, email: 'hanako.suzuki@example.com' },
      { id: 3, name: '高橋健',     age: 22, email: 'ken.takahashi@example.com' },
      { id: 4, name: '田中美咲',   age: 19, email: 'misaki.tanaka@example.com' },
      { id: 5, name: '伊藤翔',     age: 41, email: 'sho.ito@example.com' },
    ];

    function printUser(user) {
      console.log(`ID: ${user.id}/名前: ${user.name}/年齢: ${user.age}歳/メール: ${user.email}`);
    }

    function printUserList(users) {
      console.log('--- ユーザー一覧 ---');
      for (const user of users) {
        printUser(user);
      }
      console.log('--- ユーザー一覧ここまで ---');
    }

    console.log('--- ユーザー一覧を表示 ---');
    printUserList(users);

    console.log('--- 安全なユーザー検索 ---');

    function searchUsersByNameSafe(users, keyword) {
      if (typeof keyword !== 'string') {
        return [];
      }

      const trimmed = keyword.trim();
      if (trimmed === '') {
        return [];
      }

      const lowerKeyword = trimmed.toLowerCase();
      const result = [];

      for (const user of users) {
        const lowerName = user.name.toLowerCase();
        if (lowerName.includes(lowerKeyword)) {
          result.push(user);
        }
      }

      return result;
    }

    function printSearchUsersSafe(users, keyword) {
      console.log(`--- ユーザー検索(キーワード: "${keyword}") ---`);

      const result = searchUsersByNameSafe(users, keyword);

      if (result.length === 0) {
        console.log('該当するユーザーは見つかりませんでした。');
        console.log('キーワードを変えて再度お試しください。');
      } else {
        printUserList(result);
      }

      console.log('--- ユーザー検索ここまで ---');
    }

    printSearchUsersSafe(users, '佐藤');
    printSearchUsersSafe(users, '  花子  ');
    printSearchUsersSafe(users, '');
    printSearchUsersSafe(users, 123);

    console.log('--- 安全な年齢フィルター ---');

    function filterUsersByMinAgeSafe(users, minAge) {
      if (typeof minAge !== 'number' || Number.isNaN(minAge) || minAge < 0) {
        return [];
      }

      const result = [];

      for (const user of users) {
        if (typeof user.age !== 'number' || Number.isNaN(user.age)) {
          continue;
        }

        if (user.age >= minAge) {
          result.push(user);
        }
      }

      return result;
    }

    function printFilteredUsersByMinAgeSafe(users, minAge) {
      console.log(`--- 年齢フィルター(${minAge}歳以上) ---`);

      const result = filterUsersByMinAgeSafe(users, minAge);

      if (result.length === 0) {
        console.log('条件に合うユーザーは見つかりませんでした。');
        console.log('年齢の条件やデータを確認してください。');
      } else {
        printUserList(result);
      }

      console.log('--- 年齢フィルターここまで ---');
    }

    printFilteredUsersByMinAgeSafe(users, 30);
    printFilteredUsersByMinAgeSafe(users, -10);
    printFilteredUsersByMinAgeSafe(users, '30');

    console.log('--- 安全なソート(昇順・降順) ---');

    function sortUsersByAge(users, order = 'asc') {
      const copied = [...users];

      copied.sort((a, b) => {
        const ageA = (typeof a.age === 'number' && !Number.isNaN(a.age)) ? a.age : 0;
        const ageB = (typeof b.age === 'number' && !Number.isNaN(b.age)) ? b.age : 0;

        if (order === 'asc') {
          return ageA - ageB;
        } else if (order === 'desc') {
          return ageB - ageA;
        } else {
          return ageA - ageB;
        }
      });

      return copied;
    }

    function printSortedUsersByAge(users, order) {
      const label = order === 'desc' ? '年齢降順ソート(年上順)' : '年齢昇順ソート(若い順)';

      console.log(`--- ${label} ---`);

      const sorted = sortUsersByAge(users, order);
      printUserList(sorted);

      console.log(`--- ${label}ここまで ---`);
    }

    printSortedUsersByAge(users, 'asc');
    printSortedUsersByAge(users, 'desc');
    printSortedUsersByAge(users, 'xxx');

    console.log('--- 安全なユーザー追加 ---');

    function validateNewUser(newUser) {
      if (typeof newUser.id !== 'number' || Number.isNaN(newUser.id)) {
        return { valid: false, message: 'IDが不正です。数値を指定してください。' };
      }

      if (typeof newUser.name !== 'string' || newUser.name.trim() === '') {
        return { valid: false, message: '名前が不正です。空でない文字列を指定してください。' };
      }

      if (typeof newUser.age !== 'number' || Number.isNaN(newUser.age) || newUser.age < 0) {
        return { valid: false, message: '年齢が不正です。0以上の数値を指定してください。' };
      }

      if (typeof newUser.email !== 'string' || newUser.email.trim() === '') {
        return { valid: false, message: 'メールアドレスが不正です。空でない文字列を指定してください。' };
      }

      return { valid: true, message: 'OK' };
    }

    function addUserSafe(users, newUser) {
      const result = validateNewUser(newUser);

      if (!result.valid) {
        console.log('ユーザー追加に失敗しました:' + result.message);
        return false;
      }

      const exists = users.some(user => user.id === newUser.id);
      if (exists) {
        console.log('ユーザー追加に失敗しました:同じIDのユーザーが既に存在します。');
        return false;
      }

      users.push(newUser);
      console.log('ユーザーを追加しました:', newUser);
      return true;
    }

    const validUser = {
      id: 6,
      name: '山本優',
      age: 25,
      email: 'yu.yamamoto@example.com',
    };

    const invalidUser = {
      id: 'abc',
      name: '',
      age: -10,
      email: '',
    };

    console.log('追加前:');
    printUserList(users);

    console.log('妥当なユーザーを追加します');
    addUserSafe(users, validUser);

    console.log('不正なユーザーを追加しようとします');
    addUserSafe(users, invalidUser);

    console.log('追加後:');
    printUserList(users);

    console.log('--- Day 28 後半:データ処理演習②の練習が完了しました ---');
  </script>
</body>
</html>

Day 28 後半のまとめ

Day 28後半では、

  • 検索・フィルター・ソート・追加に「入力チェック」と「安全な振る舞い」を組み込んだこと
  • 元データを壊さないソートや、不正な値を受け止めるフィルターなど、 “防御的なコード”の書き方を体験したこと
  • ユーザー追加時に最低限のバリデーションとID重複チェックを入れることで、 データの信頼性を守る感覚を持ったこと

を確認しました。

ここまで来ると、 「ユーザーデータを安全に扱える小さなツール」 が手元にできています。

この考え方は、 商品データ・ログデータ・設定情報など、 ほぼすべてのデータ処理に応用できますので、 ぜひ自分なりのルールやチェック項目を足しながら、 “信頼できるコード”へ育てていってください。

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