04
🚀 創業編 Chapter 04

動き出すページ

JavaScriptでインタラクティブな体験を作る

約55分
JavaScript基礎 · intro DOM操作 · intro イベント処理 · intro
目次(33セクション)
🎬 Story — Introduction

海風テラスのデザインリニューアルをMikaに見せた日の夜。チーム3人はコワーキングスペースで今後の計画を話し合っていた。


Mika: 「デザイン、本当に素敵です!ところで、予約フォームってどうなりますか?今、電話とSNSのDMで予約を受けてるんですけど、漏れが多くて…」

あなた: 「あと、メニューの”ドリンクだけ見たい”とか”デザートだけ”とか、絞り込めると便利じゃないですか?」

Mika: 「それ!お客さんからもよく言われます。あと、ハンバーガーメニューっていうんですか?スマホで三本線をタップしたらメニューが出てくるやつ。あれも欲しいです。」

あなた: 「予約フォーム、メニュー絞り込み、ハンバーガーメニュー…これ全部HTMLとCSSだけでは無理ですよね?」

Yuki: 「そう、ここからがJavaScriptの出番。HTMLが”何を表示するか”、CSSが”どう見せるか”を担当してたよね。JavaScriptは”どう動くか”を担当する言語だよ。」


翌朝、Yukiが小さなデモを用意してきた。ブラウザでボタンを押すと色が変わり、テキストが入れ替わる。

Yuki: 「JavaScriptを使えば、ページの要素を自由に操作できる。テキストを変えたり、クラスを追加したり、表示/非表示を切り替えたり。まずは基本的な文法を覚えて、それからDOMの操作とイベント処理を学んでいこう。」

あなた: 「DOM…ですか?」

Yuki: 「Document Object Model。HTMLをJavaScriptから操作するための仕組みだよ。HTMLの要素をJavaScriptの”オブジェクト”として扱えるようにするんだ。詳しくは順番にやっていこう。」

JavaScript基礎 — 変数・型・基本文法

JavaScriptはWebページに「動き」を与える言語。ブラウザが直接実行できる唯一のプログラミング言語だ。

Yuki: 「HTMLとCSSが”静止画”なら、JavaScriptは”映画”にする技術。ユーザーの操作に反応して、ページがリアルタイムに変化するんだ。」

JavaScriptの書き場所

HTMLファイルに <script> タグで読み込む:

<!-- 方法1: 外部ファイル(推奨) -->
<script src="script.js"></script>

<!-- 方法2: HTML内に直接書く -->
<script>
  console.log("Hello, JavaScript!");
</script>

重要: <script> タグは </body> の直前に置くのが基本。HTMLの読み込みが終わってからJSを実行するためだ。

変数の宣言

JavaScriptで値を保存するには変数を使う:

// const: 変更しない値(定数)
const cafeName = "海風テラス";
const maxSeats = 30;

// let: 変更する値
let currentGuests = 12;
currentGuests = 15; // OK

// var: 古い書き方(使わない)

Yuki: 「基本は const を使って、変更が必要なときだけ let にする。var は古い書き方だから、新しいコードでは使わないよ。」

データ型

用途
文字列(String)"海風テラス", '予約完了'テキスト
数値(Number)980, 3.14金額、計算
真偽値(Boolean)true, false判定結果
配列(Array)["そば", "タコライス"]複数の値のリスト
オブジェクト(Object){ name: "Mika", age: 28 }関連するデータの集合
null / undefinednull, undefined値がない状態
// 文字列
const menuItem = "島豆腐チャンプルー";

// 数値
const price = 980;

// 真偽値
const isOpen = true;

// 配列
const categories = ["フード", "ドリンク", "デザート"];

// オブジェクト
const reservation = {
  name: "田中太郎",
  date: "2026-04-01",
  guests: 3
};

テンプレートリテラル

文字列の中に変数を埋め込む便利な方法:

const name = "田中";
const guests = 3;

// 古い書き方(+で連結)
const msg1 = name + "様、" + guests + "名でご予約ですね。";

// テンプレートリテラル(バッククォート ``)
const msg2 = `${name}様、${guests}名でご予約ですね。`;
// → "田中様、3名でご予約ですね。"

条件分岐

const hour = new Date().getHours();

if (hour < 11) {
  console.log("モーニングメニューです");
} else if (hour < 15) {
  console.log("ランチメニューです");
} else {
  console.log("ディナーメニューです");
}

配列の操作

const menu = ["沖縄そば", "タコライス", "海ぶどうサラダ"];

// 要素の取得(インデックスは0から)
console.log(menu[0]); // "沖縄そば"

// 要素の追加
menu.push("ゴーヤチャンプルー");

// 繰り返し処理
menu.forEach(item => {
  console.log(`- ${item}`);
});

// 条件で絞り込み
const longNames = menu.filter(item => item.length > 4);

console.log — デバッグの味方

console.log() はブラウザのコンソールに値を出力する。開発中のデバッグに必須:

const price = 980;
const tax = price * 0.1;
console.log("税込:", price + tax); // コンソールに "税込: 1078" と表示

const reservation = { name: "田中", guests: 3 };
console.log(reservation); // オブジェクトの中身が見える

ブラウザの開発者ツール(F12)→ Console タブで確認できる。

ポイント

  • const を基本に使い、変更が必要なときだけ let を使う
  • テンプレートリテラル(`)で文字列に変数を埋め込める
  • 配列は []、オブジェクトは {} で作る
  • console.log() はデバッグの必須ツール
  • <script> タグは </body> の直前に置く

関数 — 処理をまとめて再利用する

プログラミングで同じ処理を何度も書くのは非効率だ。関数を使えば、処理をまとめて名前をつけ、何度でも呼び出せる。

Yuki: 「関数はレシピみたいなもの。一度書いておけば、材料(引数)を変えるだけで同じ手順を繰り返せるんだ。」

関数の基本

// 関数の定義
function greetCustomer(name) {
  return `${name}様、いらっしゃいませ!`;
}

// 関数の呼び出し
const message = greetCustomer("田中");
console.log(message); // "田中様、いらっしゃいませ!"
用語意味
引数(パラメータ)関数に渡す入力値
戻り値(return)関数が返す結果
呼び出し関数を実行すること

アロー関数

ES6以降で使えるモダンな書き方:

// 従来の関数
function add(a, b) {
  return a + b;
}

// アロー関数
const add = (a, b) => {
  return a + b;
};

// 1行なら {} と return を省略できる
const add = (a, b) => a + b;

// 引数が1つなら () も省略できる
const double = n => n * 2;

Yuki: 「現場ではアロー関数をよく使うよ。特にコールバック関数(後で説明する)で大活躍する。」

実用的な関数を作ろう

税込価格の計算

const calcTaxPrice = (price, taxRate = 0.1) => {
  return Math.floor(price * (1 + taxRate));
};

console.log(calcTaxPrice(980));     // 1078
console.log(calcTaxPrice(980, 0.08)); // 1058

taxRate = 0.1 はデフォルト引数。値が渡されなければ0.1が使われる。

メニューの絞り込み

const menuItems = [
  { name: "沖縄そば", category: "food", price: 850 },
  { name: "マンゴースムージー", category: "drink", price: 650 },
  { name: "紅芋タルト", category: "dessert", price: 450 },
  { name: "タコライス", category: "food", price: 780 },
  { name: "シークヮーサージュース", category: "drink", price: 400 }
];

const filterByCategory = (items, category) => {
  return items.filter(item => item.category === category);
};

const drinks = filterByCategory(menuItems, "drink");
console.log(drinks);
// [{ name: "マンゴースムージー", ... }, { name: "シークヮーサージュース", ... }]

予約のバリデーション

const validateReservation = (name, date, guests) => {
  const errors = [];

  if (!name || name.trim() === "") {
    errors.push("お名前を入力してください");
  }

  if (!date) {
    errors.push("日付を選択してください");
  }

  if (guests < 1 || guests > 10) {
    errors.push("人数は1〜10名で指定してください");
  }

  return {
    isValid: errors.length === 0,
    errors: errors
  };
};

const result = validateReservation("", "2026-04-01", 15);
console.log(result);
// { isValid: false, errors: ["お名前を入力してください", "人数は1〜10名で指定してください"] }

コールバック関数

関数を別の関数に引数として渡すパターン。JavaScriptでは非常によく使う:

// forEach にアロー関数を渡す
const prices = [850, 650, 450];
prices.forEach(price => {
  console.log(`¥${price}`);
});

// setTimeout: 一定時間後に実行
setTimeout(() => {
  console.log("3秒経ちました!");
}, 3000);

配列メソッドと関数の組み合わせ

const menuItems = [
  { name: "沖縄そば", price: 850 },
  { name: "タコライス", price: 780 },
  { name: "マンゴースムージー", price: 650 }
];

// map: 各要素を変換した新しい配列を作る
const menuNames = menuItems.map(item => item.name);
// ["沖縄そば", "タコライス", "マンゴースムージー"]

// filter: 条件に合う要素だけの配列を作る
const expensive = menuItems.filter(item => item.price >= 800);
// [{ name: "沖縄そば", price: 850 }]

// find: 条件に合う最初の1つを返す
const soba = menuItems.find(item => item.name === "沖縄そば");
// { name: "沖縄そば", price: 850 }

ポイント

  • 関数は処理をまとめて再利用するための仕組み
  • アロー関数(=>)がモダンな書き方。コールバックで特に便利
  • デフォルト引数で省略可能なパラメータを作れる
  • map, filter, find は配列操作の三種の神器
  • 関数は「1つの関数に1つの責務」を意識する

DOM操作 — HTMLをJavaScriptで制御する

DOM(Document Object Model)は、HTMLドキュメントをJavaScriptのオブジェクトとして扱うための仕組み。これを使えば、ページの内容をリアルタイムに書き換えられる。

Yuki: 「DOMを理解すると、HTMLが”静的な書類”から”操り人形”に変わるよ。JavaScriptが糸を引いて、好きなように動かせるんだ。」

要素の取得

HTMLの要素をJavaScriptで操作するには、まず「取得」する必要がある:

// IDで取得(1つだけ)
const header = document.getElementById("site-header");

// CSSセレクタで取得(最初の1つ)
const firstCard = document.querySelector(".menu-card");

// CSSセレクタで取得(すべて)
const allCards = document.querySelectorAll(".menu-card");
メソッド戻り値用途
getElementById("id")要素1つIDで特定の要素を取得
querySelector("セレクタ")要素1つ(最初のもの)CSSセレクタで柔軟に取得
querySelectorAll("セレクタ")全要素のリスト複数要素をまとめて取得

Yuki:querySelector が一番汎用的だよ。CSSのセレクタがそのまま使えるから。」

テキストの変更

const title = document.querySelector("h1");

// テキスト内容を変更
title.textContent = "海風テラス — Ocean Breeze";

// HTMLを含む内容を変更
title.innerHTML = "海風テラス <small>Ocean Breeze</small>";
プロパティ特徴
textContentテキストのみ(安全)
innerHTMLHTMLタグを含められる(XSSに注意)

スタイルの変更

const hero = document.querySelector(".hero");

// 直接スタイルを変更
hero.style.backgroundColor = "#1a5276";
hero.style.padding = "40px";

// クラスの追加・削除(推奨)
hero.classList.add("active");
hero.classList.remove("hidden");
hero.classList.toggle("open");  // あれば外す、なければ付ける

Yuki: 「スタイルは直接変更するより、クラスを付け替える方が管理しやすいよ。スタイルの定義はCSSに任せるのがベストプラクティス。」

/* CSSでクラスを定義 */
.hidden { display: none; }
.active { background-color: #e67e22; color: white; }
// JavaScriptでクラスを切り替え
element.classList.toggle("hidden");

属性の操作

const img = document.querySelector(".cafe-photo");

// 属性の取得
const src = img.getAttribute("src");

// 属性の設定
img.setAttribute("src", "new-photo.jpg");
img.setAttribute("alt", "リニューアルした店内");

// data属性
const card = document.querySelector(".menu-card");
const category = card.dataset.category; // data-category="food" → "food"

要素の作成と追加

新しいHTML要素を動的に作れる:

// 新しい要素を作成
const newCard = document.createElement("div");
newCard.classList.add("menu-card");
newCard.innerHTML = `
  <h3>新メニュー:海ぶどう丼</h3>
  <p>プチプチ食感が楽しい海ぶどうをたっぷり</p>
  <span class="price">¥1,100</span>
`;

// 既存の要素の中に追加
const menuSection = document.querySelector("#menu");
menuSection.appendChild(newCard);

メニュー絞り込みを作ってみよう

海風テラスのメニュー絞り込み機能の基本的な仕組み:

<div class="filter-buttons">
  <button class="filter-btn active" data-category="all">すべて</button>
  <button class="filter-btn" data-category="food">フード</button>
  <button class="filter-btn" data-category="drink">ドリンク</button>
  <button class="filter-btn" data-category="dessert">デザート</button>
</div>

<div class="menu-grid">
  <div class="menu-card" data-category="food">沖縄そば</div>
  <div class="menu-card" data-category="drink">マンゴースムージー</div>
  <div class="menu-card" data-category="dessert">紅芋タルト</div>
</div>
const filterMenu = (category) => {
  const cards = document.querySelectorAll(".menu-card");

  cards.forEach(card => {
    if (category === "all" || card.dataset.category === category) {
      card.classList.remove("hidden");
    } else {
      card.classList.add("hidden");
    }
  });
};

ポイント

  • querySelector / querySelectorAll で要素を取得する
  • テキスト変更は textContent、HTML変更は innerHTML
  • スタイル変更は classList でクラスを切り替えるのが推奨
  • data-* 属性で要素にカスタムデータを持たせられる
  • createElement + appendChild で動的に要素を追加できる

イベント処理 — ユーザーの操作に反応する

ユーザーがボタンをクリックした、フォームに入力した、スクロールした——こういった操作を「イベント」と呼ぶ。JavaScriptでイベントを検知し、それに応じた処理を実行するのがイベント処理だ。

Yuki: 「イベント処理は”アクション映画のスタントコーディネーター”みたいなもの。“このボタンが押されたら、こうする”というシナリオを書いておくんだ。」

addEventListener — イベントリスナーの登録

const button = document.querySelector("#reserve-btn");

button.addEventListener("click", () => {
  console.log("ボタンがクリックされました!");
});

addEventListener は3つの部分で構成される:

  1. 対象の要素 — どの要素で
  2. イベント名 — 何が起きたら
  3. コールバック関数 — 何をするか

よく使うイベント一覧

イベント発生タイミング用途
clickクリック時ボタン、リンク
submitフォーム送信時予約フォーム
input入力内容が変わった時リアルタイムバリデーション
change値が確定した時セレクトボックス
keydownキーを押した時ショートカットキー
scrollスクロール時スクロールアニメーション
DOMContentLoadedHTML読み込み完了時初期化処理

クリックイベントの実例

ハンバーガーメニュー

<button class="hamburger" id="menu-toggle">
  <span></span><span></span><span></span>
</button>
<nav id="mobile-nav" class="mobile-nav">
  <ul>
    <li><a href="#menu">メニュー</a></li>
    <li><a href="#access">アクセス</a></li>
    <li><a href="#hours">営業時間</a></li>
  </ul>
</nav>
const menuToggle = document.querySelector("#menu-toggle");
const mobileNav = document.querySelector("#mobile-nav");

menuToggle.addEventListener("click", () => {
  mobileNav.classList.toggle("open");
  menuToggle.classList.toggle("active");
});
.mobile-nav {
  display: none;
}
.mobile-nav.open {
  display: block;
}

メニューフィルター

const filterButtons = document.querySelectorAll(".filter-btn");

filterButtons.forEach(button => {
  button.addEventListener("click", () => {
    // アクティブなボタンのスタイルを切り替え
    filterButtons.forEach(btn => btn.classList.remove("active"));
    button.classList.add("active");

    // メニューを絞り込み
    const category = button.dataset.category;
    filterMenu(category);
  });
});

フォームイベント

予約フォームの実装

<form id="reservation-form">
  <div class="form-group">
    <label for="name">お名前</label>
    <input type="text" id="name" name="name" required>
    <span class="error-msg" id="name-error"></span>
  </div>

  <div class="form-group">
    <label for="date">ご予約日</label>
    <input type="date" id="date" name="date" required>
  </div>

  <div class="form-group">
    <label for="guests">人数</label>
    <input type="number" id="guests" name="guests" min="1" max="10" required>
  </div>

  <button type="submit" class="btn btn-primary">予約する</button>
</form>

<div id="result" class="hidden"></div>
const form = document.querySelector("#reservation-form");

form.addEventListener("submit", (event) => {
  // デフォルトのフォーム送信を停止
  event.preventDefault();

  // 入力値を取得
  const name = document.querySelector("#name").value;
  const date = document.querySelector("#date").value;
  const guests = document.querySelector("#guests").value;

  // バリデーション
  const validation = validateReservation(name, date, Number(guests));

  if (!validation.isValid) {
    alert(validation.errors.join("\n"));
    return;
  }

  // 成功時の処理
  const result = document.querySelector("#result");
  result.classList.remove("hidden");
  result.innerHTML = `
    <h3>ご予約を受け付けました</h3>
    <p>${name}様 / ${date} / ${guests}名</p>
  `;
});

event.preventDefault() — デフォルト動作の抑止

ブラウザには要素ごとにデフォルトの動作がある:

要素デフォルト動作preventDefault() で
<form>ページ遷移してフォーム送信JavaScriptで処理する
<a>リンク先に移動独自の処理を実行
// フォーム送信をJSで制御
form.addEventListener("submit", (event) => {
  event.preventDefault(); // ページ遷移を防ぐ
  // JavaScriptで送信処理を行う
});

リアルタイムバリデーション

input イベントで入力中にチェックできる:

const nameInput = document.querySelector("#name");
const nameError = document.querySelector("#name-error");

nameInput.addEventListener("input", () => {
  if (nameInput.value.trim() === "") {
    nameError.textContent = "お名前を入力してください";
    nameInput.classList.add("input-error");
  } else {
    nameError.textContent = "";
    nameInput.classList.remove("input-error");
  }
});
.input-error {
  border-color: #e74c3c;
}
.error-msg {
  color: #e74c3c;
  font-size: 0.85rem;
}

DOMContentLoaded — 初期化のタイミング

document.addEventListener("DOMContentLoaded", () => {
  // HTMLの読み込みが完了してから実行される
  console.log("ページの準備完了!");
  initializeMenu();
  setupEventListeners();
});

<script> タグを </body> 直前に置いている場合は不要だが、<head> 内に置く場合は DOMContentLoaded で囲む必要がある。

ポイント

  • addEventListener でイベントリスナーを登録する
  • click, submit, input が最もよく使うイベント
  • event.preventDefault() でデフォルト動作を抑止できる
  • フォームの submit イベントでバリデーションを行う
  • classList.toggle() でクラスの付け外しが簡単にできる
  • 入力中のリアルタイムチェックには input イベントを使う
📖 Story — Conclusion

ブラウザの中で、海風テラスのサイトが「生きている」。

ハンバーガーメニューをタップするとナビゲーションがスライドして現れる。メニューセクションでは「ドリンク」ボタンを押すとドリンクだけが表示される。予約フォームに名前と日時を入力して送信ボタンを押すと、バリデーションが走り、確認メッセージが表示される。


あなた: 「すげえ…完全にちゃんとしたWebサイトじゃん。これ、本当にうちらが作ったの?」

Mika: 「ありがとうございます!これなら予約の管理がずっと楽になります。ところで…このサイト、いつ公開できますか?友人にも紹介したいんです。」

あなた: 「公開…?そうか、今は僕のパソコンの中でしか見られないんですよね。」

Yuki: 「そう。今は localhost で動いてるだけだからね。世界中の人がアクセスできるようにするには、デプロイ(公開)が必要だよ。サーバーにファイルを置いて、ドメインを設定して、HTTPSで安全に接続できるようにする。」

あなた: 「ドメインって、“umikaze-terrace.com” みたいなやつ?」

Yuki: 「そう。あとGitのブランチ運用も覚えないとね。複数人で開発するとき、メインのコードを壊さないようにする仕組みだよ。」

あなた: 「デプロイかぁ。いよいよ世の中に出すんですね。緊張するけど…ワクワクします。」

Yuki: 「その気持ちを大事にして。ローンチの瞬間は何度経験しても特別だよ。」


次のチャプター: Chapter 5: 世界に公開 — Git のブランチ運用を学び、海風テラスのサイトをインターネットに公開する。ドメイン、DNS、HTTPSの設定に挑む。

🧠 理解度チェック

Q1.JavaScriptで変更しない値を宣言するキーワードはどれ?

💡 カフェの名前や最大席数など、変わらない値をconst で定義したよね。

Q2.テンプレートリテラルで変数を埋め込む正しい書き方はどれ?

💡 予約確認メッセージに名前や人数を埋め込むときに使ったよね。

Q3.document.querySelector('.menu-card') は何を返す?

💡 メニューカードをJavaScriptで操作するために、まず要素を取得したよね。

Q4.要素のCSSクラスを付け外しする(あれば外す、なければ付ける)メソッドはどれ?

💡 ハンバーガーメニューの開閉で、openクラスを付けたり外したりしたよね。

Q5.フォームのsubmitイベントで event.preventDefault() を呼ぶ理由は?

💡 予約フォームの送信をJavaScriptで処理するために使った重要なメソッドだ。

Q6.アロー関数の正しい書き方はどれ?

💡 メニューの絞り込みやコールバック関数で、何度もアロー関数を使ったね。

Q7.配列 [10, 20, 30] から20以上の要素だけを取り出すメソッドはどれ?

💡 メニューをカテゴリで絞り込むときに使った配列メソッドだ。

Q8.要素のテキスト内容を安全に変更するプロパティはどれ?

💡 予約確認メッセージの表示で、安全な方法としてYukiが教えてくれたよね。

よくある質問

JavaScriptが実行されない・エラーが出る

基本のチェックリスト: **1. `<script>` タグの位置** ```html <!-- </body> の直前に置く --> <script src="script.js"></script> </body> ``` **2. ファイルパスの確認** ```html <!-- HTMLファイルと同じフォルダなら --> <script src="script.js"></script> <!-- jsフォルダ内なら --> <script src="js/script.js"></script> ``` **3. コンソールでエラー確認** - `F12` → Console タブでエラーメッセージを確認 - 赤いエラーの行番号をクリックすると、問題箇所に飛べる **4. よくある構文エラー** - セミコロン `;` の漏れ - 括弧 `()` `{}` `[]` の閉じ忘れ - スペルミス(`documnet` → `document`)

const と let の使い分けがわからない

シンプルなルール: | キーワード | 使うとき | 例 | |-----------|---------|----| | `const` | **基本はこれ** | 関数、設定値、DOM要素 | | `let` | 値を変更する必要があるとき | カウンター、状態フラグ | ```javascript // const:再代入できない const cafeName = "海風テラス"; cafeName = "別の名前"; // エラー! // let:再代入できる let count = 0; count = count + 1; // OK // 配列やオブジェクトのconst:中身は変更OK const items = []; items.push("沖縄そば"); // OK(配列自体を変えてないから) ``` **迷ったらまず `const`**。後で変更が必要になったら `let` に変えましょう。

querySelector で要素が取得できない(null になる)

原因は主に3つ: **1. スクリプトの実行タイミングが早い** ```html <!-- 問題:headで読み込むとHTMLがまだない --> <head> <script src="script.js"></script> </head> <!-- 解決:bodyの最後で読み込む --> <script src="script.js"></script> </body> ``` **2. セレクタが間違っている** ```javascript // クラスにはドット(.)を忘れずに document.querySelector("menu-card"); // NG document.querySelector(".menu-card"); // OK // IDにはシャープ(#) document.querySelector("header"); // <header>タグ document.querySelector("#header"); // id="header" ``` **3. HTMLのclass/id名にタイプミス** - HTMLとJavaScriptで完全に一致しているか確認

addEventListenerが動かない

チェックポイント: **1. 要素が正しく取得できているか** ```javascript const btn = document.querySelector("#reserve-btn"); console.log(btn); // null ならセレクタが間違っている ``` **2. イベント名が正しいか** ```javascript // 正しい btn.addEventListener("click", () => { ... }); // 間違い btn.addEventListener("Click", () => { ... }); // 大文字 btn.addEventListener("onclick", () => { ... }); // on不要 ``` **3. コールバックが関数になっているか** ```javascript // 正しい:関数を渡す btn.addEventListener("click", handleClick); // 間違い:関数を実行してしまっている btn.addEventListener("click", handleClick()); // () が余計 ```

フォームの入力値が取得できない

フォーム要素の値は `.value` プロパティで取得します: ```javascript // テキスト入力 const name = document.querySelector("#name").value; // 数値入力(文字列として取得される) const guests = document.querySelector("#guests").value; console.log(typeof guests); // "string" // 数値に変換する const guestsNum = Number(guests); ``` **注意点**: - `input.value` は常に**文字列**を返す - 数値が欲しい場合は `Number()` で変換 - `textContent` ではなく `value` を使う(inputは表示テキストではなく入力値) - `submit` イベント内で取得するタイミングは正しいか確認

=== と == の違いは?

JavaScriptには2種類の等価演算子があります: | 演算子 | 名前 | 特徴 | |--------|------|------| | `===` | 厳密等価 | 型も値も同じなら true | | `==` | 等価 | 型変換してから比較 | ```javascript // === の場合(推奨) 1 === "1" // false(数値と文字列で型が違う) 1 === 1 // true // == の場合(非推奨) 1 == "1" // true(型変換されてしまう) 0 == false // true(予期しない結果になりやすい) ``` **ルール**: 常に `===` を使う。`==` は予期しないバグの原因になります。

forEach と map の違いがわからない

| メソッド | 戻り値 | 用途 | |---------|--------|------| | `forEach` | なし(undefined) | 各要素に対して処理を実行 | | `map` | **新しい配列** | 各要素を変換した配列を作る | ```javascript const prices = [850, 650, 450]; // forEach: 表示するだけ(戻り値なし) prices.forEach(p => console.log(p)); // map: 税込価格の配列を作る(新しい配列が返る) const taxPrices = prices.map(p => Math.floor(p * 1.1)); // [935, 715, 495] ``` **判断基準**: 結果の配列が欲しい → `map`、ただ処理したいだけ → `forEach`

「Cannot read properties of null」エラーが出る

このエラーは、`null`(存在しないもの)のプロパティにアクセスしようとすると発生します。 **最もよくある原因**: `querySelector` で要素が見つからなかった ```javascript const btn = document.querySelector("#reserv-btn"); // タイプミス! console.log(btn); // null btn.addEventListener("click", ...); // Error! ``` **解決方法**: 1. セレクタのスペルを確認 2. HTML要素が存在するか確認 3. スクリプトの実行タイミングを確認 **安全なコード**: ```javascript const btn = document.querySelector("#reserve-btn"); if (btn) { btn.addEventListener("click", () => { ... }); } ```

innerHTML と textContent のどちらを使うべき?

**基本は `textContent` を使いましょう**。 | プロパティ | 扱い | 安全性 | |-----------|------|--------| | `textContent` | プレーンテキスト | 安全(HTMLタグが無効化される) | | `innerHTML` | HTML | **XSS攻撃の危険あり** | ```javascript const userInput = '<script>alert("攻撃!")</script>'; // textContent: テキストとして表示(安全) element.textContent = userInput; // → 文字列としてそのまま表示される // innerHTML: HTMLとして解釈される(危険) element.innerHTML = userInput; // → スクリプトが実行される可能性がある ``` **innerHTML を使うとき**: 信頼できるHTMLを動的に追加する場合のみ。ユーザー入力は絶対に innerHTML に入れない。

console.log の使い方とデバッグのコツ

**基本の使い方**: ```javascript // 値の確認 console.log("名前:", name); // オブジェクトの中身を見る console.log(reservation); // 複数の値を同時に console.log("price:", price, "tax:", tax); ``` **デバッグのコツ**: 1. **怪しい箇所の前後**に `console.log` を入れる 2. **変数の型**を確認: `console.log(typeof value)` 3. **条件分岐**の中に入れて、どの分岐に入ったか確認 4. **イベント内**に入れて、イベントが発火しているか確認 ```javascript btn.addEventListener("click", () => { console.log("クリックされた!"); // まずこれが表示されるか確認 const value = input.value; console.log("入力値:", value); // 値が取れているか確認 }); ``` 確認が終わったら `console.log` は削除しましょう。