🧩
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();