# フロントエンドのためのJavaScript完全ガイド ## JavaScriptとは JavaScriptは、Webページに動的な機能を追加するプログラミング言語です。ブラウザ上で動作し、ユーザーインタラクションの処理、DOM操作、非同期通信など、モダンなWebアプリケーションに不可欠な機能を提供します。 ## JavaScript基礎 ### 変数と定数 ```javascript // var(古い書き方、使用は推奨されない) var oldVariable = "古い方式"; // let(再代入可能) let userName = "太郎"; userName = "花子"; // 再代入可能 // const(再代入不可) const API_URL = "https://api.example.com"; const userInfo = { name: "太郎", age: 25 }; // userInfo = {}; // エラー:再代入不可 userInfo.name = "花子"; // オブジェクトの中身は変更可能 ``` ### データ型 ```javascript // プリミティブ型 const number = 42; const string = "Hello World"; const boolean = true; const nullValue = null; const undefinedValue = undefined; const symbol = Symbol("unique"); const bigint = 123n; // オブジェクト型 const array = [1, 2, 3, "four", true]; const object = { name: "太郎", age: 30, hobbies: ["読書", "映画鑑賞"] }; const func = function() { return "Hello"; }; // 型の確認 console.log(typeof number); // "number" console.log(typeof string); // "string" console.log(typeof boolean); // "boolean" console.log(Array.isArray(array)); // true ``` ### 関数 ```javascript // 関数宣言 function greet(name) { return `こんにちは、${name}さん!`; } // 関数式 const greetFunction = function(name) { return `こんにちは、${name}さん!`; }; // アロー関数 const greetArrow = (name) => { return `こんにちは、${name}さん!`; }; // アロー関数(短縮形) const greetShort = name => `こんにちは、${name}さん!`; // 複数パラメータ const add = (a, b) => a + b; // デフォルトパラメータ const greetWithDefault = (name = "ゲスト") => `こんにちは、${name}さん!`; // 使用例 console.log(greet("太郎")); // "こんにちは、太郎さん!" console.log(add(5, 3)); // 8 console.log(greetWithDefault()); // "こんにちは、ゲストさん!" ``` ## DOM操作 ### 要素の取得 ```javascript // IDで取得 const header = document.getElementById("header"); // クラス名で取得(複数要素) const buttons = document.getElementsByClassName("btn"); // タグ名で取得 const paragraphs = document.getElementsByTagName("p"); // CSSセレクタで取得(最初の要素) const firstButton = document.querySelector(".btn"); const specificElement = document.querySelector("#main .content"); // CSSセレクタで取得(すべての要素) const allButtons = document.querySelectorAll(".btn"); const allLinks = document.querySelectorAll("a[href^='https']"); ``` ### 要素の操作 ```javascript // 要素の作成 const newDiv = document.createElement("div"); const newText = document.createTextNode("新しいテキスト"); // 属性の操作 const link = document.querySelector("a"); link.setAttribute("href", "https://example.com"); link.getAttribute("href"); // "https://example.com" link.removeAttribute("target"); // クラスの操作 const element = document.querySelector(".container"); element.classList.add("active"); element.classList.remove("inactive"); element.classList.toggle("highlighted"); element.classList.contains("active"); // true/false // テキスト内容の変更 element.textContent = "新しいテキスト"; element.innerHTML = "HTML付きテキスト"; // スタイルの変更 element.style.color = "red"; element.style.backgroundColor = "yellow"; element.style.fontSize = "16px"; ``` ### 要素の追加・削除 ```javascript // 要素の追加 const parent = document.querySelector(".parent"); const child = document.createElement("div"); child.textContent = "新しい子要素"; parent.appendChild(child); // 末尾に追加 parent.insertBefore(child, parent.firstChild); // 先頭に追加 // より柔軟な挿入 parent.insertAdjacentHTML("beforeend", "
HTML文字列
"); parent.insertAdjacentElement("afterbegin", child); // 要素の削除 child.remove(); // 要素自体を削除 parent.removeChild(child); // 親から子要素を削除 // 要素の置換 const newElement = document.createElement("span"); newElement.textContent = "置換された要素"; parent.replaceChild(newElement, child); ``` ## イベント処理 ### イベントリスナーの基本 ```javascript // イベントリスナーの追加 const button = document.querySelector("#myButton"); // 基本的な書き方 button.addEventListener("click", function(event) { console.log("ボタンがクリックされました!"); console.log("イベント:", event); }); // アロー関数を使用 button.addEventListener("click", (event) => { console.log("ボタンがクリックされました!"); }); // 名前付き関数を使用 function handleButtonClick(event) { console.log("ボタンがクリックされました!"); // イベントのデフォルト動作を防ぐ event.preventDefault(); // イベントの伝播を停止 event.stopPropagation(); } button.addEventListener("click", handleButtonClick); // イベントリスナーの削除 button.removeEventListener("click", handleButtonClick); ``` ### 各種イベントの実装例 ```javascript // フォームの処理 const form = document.querySelector("#contactForm"); const nameInput = document.querySelector("#name"); const emailInput = document.querySelector("#email"); form.addEventListener("submit", (event) => { event.preventDefault(); // ページリロードを防ぐ const formData = { name: nameInput.value, email: emailInput.value }; // バリデーション if (!formData.name || !formData.email) { alert("すべての項目を入力してください"); return; } console.log("送信データ:", formData); // API送信処理などを実行 }); // 入力値の即座な検証 emailInput.addEventListener("input", (event) => { const email = event.target.value; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (email && !emailRegex.test(email)) { event.target.style.borderColor = "red"; } else { event.target.style.borderColor = "green"; } }); // キーボードイベント document.addEventListener("keydown", (event) => { // Escキーでモーダルを閉じる if (event.key === "Escape") { closeModal(); } // Ctrl+Sで保存 if (event.ctrlKey && event.key === "s") { event.preventDefault(); saveDocument(); } }); // マウスイベント const draggableElement = document.querySelector(".draggable"); draggableElement.addEventListener("mousedown", (event) => { console.log("マウスダウン:", event.clientX, event.clientY); }); draggableElement.addEventListener("mousemove", (event) => { // ドラッグ処理 }); draggableElement.addEventListener("mouseup", (event) => { console.log("マウスアップ"); }); ``` ### イベント委譲(Event Delegation) ```javascript // 親要素にイベントリスナーを設定 const todoList = document.querySelector("#todoList"); todoList.addEventListener("click", (event) => { // 削除ボタンがクリックされた場合 if (event.target.classList.contains("delete-btn")) { const todoItem = event.target.closest(".todo-item"); todoItem.remove(); } // チェックボックスがクリックされた場合 if (event.target.classList.contains("todo-checkbox")) { const todoItem = event.target.closest(".todo-item"); todoItem.classList.toggle("completed"); } }); // 動的に要素を追加 function addTodoItem(text) { const todoItem = document.createElement("div"); todoItem.className = "todo-item"; todoItem.innerHTML = ` ${text} `; todoList.appendChild(todoItem); } ``` ## 非同期処理 ### Promise と async/await ```javascript // Promise の基本 function fetchUserData(userId) { return new Promise((resolve, reject) => { // 模擬的な非同期処理 setTimeout(() => { if (userId > 0) { resolve({ id: userId, name: "太郎", email: "taro@example.com" }); } else { reject(new Error("無効なユーザーID")); } }, 1000); }); } // Promise の使用 fetchUserData(1) .then(user => { console.log("ユーザー情報:", user); return fetchUserPosts(user.id); }) .then(posts => { console.log("投稿:", posts); }) .catch(error => { console.error("エラー:", error.message); }); // async/await の使用 async function loadUserProfile(userId) { try { const user = await fetchUserData(userId); console.log("ユーザー情報:", user); const posts = await fetchUserPosts(user.id); console.log("投稿:", posts); return { user, posts }; } catch (error) { console.error("エラー:", error.message); throw error; } } // 使用例 loadUserProfile(1) .then(profile => { console.log("プロファイル読み込み完了:", profile); }) .catch(error => { console.error("プロファイル読み込み失敗:", error); }); ``` ### Fetch API ```javascript // GET リクエスト async function fetchData() { try { const response = await fetch("https://api.example.com/users"); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error("データ取得エラー:", error); throw error; } } // POST リクエスト async function createUser(userData) { try { const response = await fetch("https://api.example.com/users", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer token123" }, body: JSON.stringify(userData) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); return result; } catch (error) { console.error("ユーザー作成エラー:", error); throw error; } } // 使用例 async function handleUserCreation() { const userData = { name: "花子", email: "hanako@example.com" }; try { const newUser = await createUser(userData); console.log("新しいユーザー:", newUser); // UI更新 displaySuccessMessage("ユーザーが正常に作成されました"); } catch (error) { displayErrorMessage("ユーザーの作成に失敗しました"); } } ``` ## 配列とオブジェクトの操作 ### 配列の高階関数 ```javascript const users = [ { id: 1, name: "太郎", age: 25, active: true }, { id: 2, name: "花子", age: 30, active: false }, { id: 3, name: "次郎", age: 28, active: true }, { id: 4, name: "久美", age: 35, active: true } ]; // map - 配列の各要素を変換 const userNames = users.map(user => user.name); console.log(userNames); // ["太郎", "花子", "次郎", "久美"] const userDisplays = users.map(user => ({ ...user, displayName: `${user.name} (${user.age}歳)` })); // filter - 条件に合う要素だけを抽出 const activeUsers = users.filter(user => user.active); const youngUsers = users.filter(user => user.age < 30); // find - 条件に合う最初の要素を取得 const specificUser = users.find(user => user.name === "太郎"); // reduce - 配列を単一の値に集約 const totalAge = users.reduce((sum, user) => sum + user.age, 0); const averageAge = totalAge / users.length; // some - 条件に合う要素が存在するかチェック const hasActiveUser = users.some(user => user.active); // every - すべての要素が条件に合うかチェック const allActive = users.every(user => user.active); // sort - 配列のソート const sortedByAge = users.sort((a, b) => a.age - b.age); const sortedByName = users.sort((a, b) => a.name.localeCompare(b.name)); ``` ### オブジェクトの操作 ```javascript const user = { name: "太郎", age: 25, email: "taro@example.com" }; // 分割代入 const { name, age, email } = user; console.log(name); // "太郎" // 残りの属性を取得 const { name: userName, ...otherProps } = user; console.log(otherProps); // { age: 25, email: "taro@example.com" } // オブジェクトのマージ const additionalInfo = { city: "東京", country: "日本" }; const completeUser = { ...user, ...additionalInfo }; // 動的なプロパティ名 const propertyName = "dynamicProp"; const dynamicObject = { [propertyName]: "動的な値", [`${propertyName}2`]: "別の動的な値" }; // オブジェクトのキーと値を取得 const keys = Object.keys(user); // ["name", "age", "email"] const values = Object.values(user); // ["太郎", 25, "taro@example.com"] const entries = Object.entries(user); // [["name", "太郎"], ["age", 25], ...] // エントリーからオブジェクトを再構築 const rebuiltUser = Object.fromEntries(entries); ``` ## 実践的な実装例 ### 動的なToDoリスト ```javascript class TodoApp { constructor() { this.todos = []; this.nextId = 1; this.init(); } init() { this.setupEventListeners(); this.render(); } setupEventListeners() { const addForm = document.querySelector("#add-todo-form"); const todoList = document.querySelector("#todo-list"); const filterButtons = document.querySelectorAll(".filter-btn"); addForm.addEventListener("submit", (e) => { e.preventDefault(); const input = e.target.querySelector("#todo-input"); this.addTodo(input.value.trim()); input.value = ""; }); todoList.addEventListener("click", (e) => { const todoId = parseInt(e.target.closest(".todo-item")?.dataset.id); if (e.target.classList.contains("toggle-btn")) { this.toggleTodo(todoId); } else if (e.target.classList.contains("delete-btn")) { this.deleteTodo(todoId); } }); filterButtons.forEach(btn => { btn.addEventListener("click", (e) => { const filter = e.target.dataset.filter; this.setFilter(filter); }); }); } addTodo(text) { if (!text) return; const todo = { id: this.nextId++, text: text, completed: false, createdAt: new Date() }; this.todos.push(todo); this.render(); } toggleTodo(id) { const todo = this.todos.find(t => t.id === id); if (todo) { todo.completed = !todo.completed; this.render(); } } deleteTodo(id) { this.todos = this.todos.filter(t => t.id !== id); this.render(); } setFilter(filter) { this.currentFilter = filter; this.render(); // フィルターボタンのアクティブ状態を更新 document.querySelectorAll(".filter-btn").forEach(btn => { btn.classList.toggle("active", btn.dataset.filter === filter); }); } getFilteredTodos() { switch (this.currentFilter) { case "active": return this.todos.filter(todo => !todo.completed); case "completed": return this.todos.filter(todo => todo.completed); default: return this.todos; } } render() { const todoList = document.querySelector("#todo-list"); const filteredTodos = this.getFilteredTodos(); todoList.innerHTML = filteredTodos.map(todo => `ユーザーが見つかりません
"; return; } container.innerHTML = usersToRender.map(user => `Email: ${this.escapeHtml(user.email)}
Company: ${this.escapeHtml(user.company.name)}
City: ${this.escapeHtml(user.address.city)}
Email: ${this.escapeHtml(user.email)}
Phone: ${this.escapeHtml(user.phone)}
Website: ${this.escapeHtml(user.website)}
Company: ${this.escapeHtml(user.company.name)}
Address: ${this.escapeHtml(user.address.street)}, ${this.escapeHtml(user.address.city)}
${this.escapeHtml(post.body)}
年齢: ${age}歳
成人: ${age >= 20 ? "はい" : "いいえ"}