海風テラスのデザインリニューアルを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 / undefined | null, 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 | テキストのみ(安全) |
innerHTML | HTMLタグを含められる(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つの部分で構成される:
- 対象の要素 — どの要素で
- イベント名 — 何が起きたら
- コールバック関数 — 何をするか
よく使うイベント一覧
| イベント | 発生タイミング | 用途 |
|---|---|---|
click | クリック時 | ボタン、リンク |
submit | フォーム送信時 | 予約フォーム |
input | 入力内容が変わった時 | リアルタイムバリデーション |
change | 値が確定した時 | セレクトボックス |
keydown | キーを押した時 | ショートカットキー |
scroll | スクロール時 | スクロールアニメーション |
DOMContentLoaded | HTML読み込み完了時 | 初期化処理 |
クリックイベントの実例
ハンバーガーメニュー
<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イベントを使う
ブラウザの中で、海風テラスのサイトが「生きている」。
ハンバーガーメニューをタップするとナビゲーションがスライドして現れる。メニューセクションでは「ドリンク」ボタンを押すとドリンクだけが表示される。予約フォームに名前と日時を入力して送信ボタンを押すと、バリデーションが走り、確認メッセージが表示される。
あなた: 「すげえ…完全にちゃんとした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` は削除しましょう。