← JavaScriptページに戻る
🧩

JavaScriptのサンプルコード

難易度が段階的に上がる3本の実践的なサンプルを紹介します。DOM操作を伴う小規模アプリ、探索・整列アルゴリズムの実装、非同期処理の使い分けという、基本情報技術者試験にも通じるテーマを扱います。

サンプル①:ToDoリスト(DOM操作の実践)

入力されたタスクを配列で管理し、状態が変わるたびに一覧をまとめて再描画するシンプルなToDoアプリです。DocumentFragmentでDOM更新をまとめ、リスト全体に1つだけイベントリスナーを付ける「イベント委譲」でクリック処理を効率化しています。

HTML
<div class="todo-app">
  <input id="new-task" type="text" placeholder="タスクを入力">
  <button id="add-btn">追加</button>
  <ul id="todo-list"></ul>
</div>
JavaScript
const tasks = []; // { id, text, done }
let nextId = 1;

const listEl = document.querySelector("#todo-list");
const inputEl = document.querySelector("#new-task");
const addBtn = document.querySelector("#add-btn");

function render() {
  listEl.innerHTML = ""; // 一旦クリアしてまとめて再描画
  const fragment = document.createDocumentFragment(); // DOM操作をまとめてreflowを抑える

  tasks.forEach(task => {
    const li = document.createElement("li");
    li.textContent = task.text;
    li.style.textDecoration = task.done ? "line-through" : "none";
    li.dataset.id = String(task.id);

    const delBtn = document.createElement("button");
    delBtn.textContent = "削除";
    delBtn.dataset.action = "delete";
    li.appendChild(delBtn);

    fragment.appendChild(li);
  });

  listEl.appendChild(fragment);
}

function addTask(text) {
  const trimmed = text.trim();
  if (!trimmed) return;
  tasks.push({ id: nextId++, text: trimmed, done: false });
  render();
}

addBtn.addEventListener("click", () => {
  addTask(inputEl.value);
  inputEl.value = "";
});

listEl.addEventListener("click", (event) => { // イベント委譲でli個別へのリスナー登録を回避
  const li = event.target.closest("li");
  if (!li) return;
  const id = Number(li.dataset.id);

  if (event.target.dataset.action === "delete") {
    const index = tasks.findIndex(t => t.id === id);
    tasks.splice(index, 1);
  } else {
    const task = tasks.find(t => t.id === id);
    task.done = !task.done;
  }
  render();
});

サンプル②:探索・整列アルゴリズムの実装

線形探索・二分探索、バブルソート・クイックソートを実装し、それぞれの計算量の違いを比較します。二分探索を使うには事前に配列がソートされている必要がある点に注意してください。

JavaScript
function linearSearch(arr, target) { // 計算量 O(n)
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === target) return i;
  }
  return -1;
}

function binarySearch(sortedArr, target) { // 計算量 O(log n)(ソート済みが前提)
  let low = 0, high = sortedArr.length - 1;
  while (low <= high) {
    const mid = Math.floor((low + high) / 2);
    if (sortedArr[mid] === target) return mid;
    if (sortedArr[mid] < target) low = mid + 1;
    else high = mid - 1;
  }
  return -1;
}

function bubbleSort(arr) { // 計算量 O(n^2)(隣接要素を交換しながら整列)
  const result = [...arr];
  for (let i = 0; i < result.length - 1; i++) {
    for (let j = 0; j < result.length - 1 - i; j++) {
      if (result[j] > result[j + 1]) {
        [result[j], result[j + 1]] = [result[j + 1], result[j]]; // 分割代入でswap
      }
    }
  }
  return result;
}

function quickSort(arr) { // 平均 O(n log n)、最悪 O(n^2)
  if (arr.length <= 1) return arr;
  const [pivot, ...rest] = arr;
  const left = rest.filter(n => n < pivot);
  const right = rest.filter(n => n >= pivot);
  return [...quickSort(left), pivot, ...quickSort(right)];
}

const data = [64, 25, 12, 22, 11, 90, 34, 5];
const sorted = quickSort(data);

console.log("元配列:", data);
console.log("バブルソート結果:", bubbleSort(data));
console.log("クイックソート結果:", sorted);
console.log("線形探索(22):", linearSearch(data, 22));        // インデックス3
console.log("二分探索(34, ソート後):", binarySearch(sorted, 34));

// データ件数が増えるほど、O(n^2)のバブルソートよりO(n log n)のクイックソートが
// 圧倒的に高速になる(例: 1万件では数百〜数千倍の差になりうる)

サンプル③:async/awaitを使った非同期処理

通信処理を模したPromiseを使い、直列実行(1件ずつ待つ)と並列実行(Promise.allでまとめて待つ)の違い、そしてtry/catch/finallyによるエラーハンドリングを組み合わせた例です。

JavaScript
function fetchUser(id) { // 通信を模したPromise
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (id <= 0) {
        reject(new Error("不正なユーザーIDです"));
        return;
      }
      resolve({ id, name: `ユーザー${id}` });
    }, 300);
  });
}

async function loadSequential(ids) { // 直列実行:1件ずつ順番に待つ(合計時間がかかる)
  const results = [];
  for (const id of ids) {
    const user = await fetchUser(id);
    results.push(user);
  }
  return results;
}

async function loadParallel(ids) { // 並列実行:同時に投げてまとめて待つ(速い)
  const promises = ids.map(id => fetchUser(id));
  return Promise.all(promises);
}

async function main() {
  try {
    console.time("直列");
    await loadSequential([1, 2, 3]);
    console.timeEnd("直列"); // 約900ms

    console.time("並列");
    await loadParallel([1, 2, 3]);
    console.timeEnd("並列"); // 約300ms

    await fetchUser(-1); // わざとエラーを発生させる
  } catch (err) {
    console.error("エラー発生:", err.message); // "不正なユーザーIDです"
  } finally {
    console.log("すべての処理が完了しました");
  }
}

main();

理解度チェッククイズに挑戦する →