この章では、JavaScriptの基礎を学び、インタラクティブなUIを作成します。
- JavaScriptがブラウザでどのように実行されるかを理解する
- DOMとは何か、なぜ重要かを理解する
- イベント駆動プログラミングの仕組みを理解する
- JavaScriptの基本文法
- 変数とデータ型
- 関数と制御構文
- DOM操作
- イベント処理
成果物: 操作で変わるインタラクティブUI
HTMLとCSSだけではできないこと:
<!-- HTMLとCSSだけ = 静的(変化しない) -->
<button>クリックしてください</button>これをクリックしても、何も起こりません。
JavaScriptを加えると = 動的(変化する):
<button onclick="alert('クリックされました!')">クリックしてください</button>クリックすると、アラートが表示されます。
3つの技術の役割を車に例えると:
HTML = 車の骨組み(フレーム、座席、ハンドルなど)
CSS = 車の外装(色、デザイン)
JavaScript = エンジンと電子制御(動く仕組み)
ステップ1: ブラウザがHTMLを読み込む
<!DOCTYPE html>
<html>
<head>
<script src="script.js"></script>
</head>
<body>
<h1 id="title">こんにちは</h1>
<button id="btn">クリック</button>
</body>
</html>ステップ2: JavaScriptエンジンが起動
ブラウザには「JavaScriptエンジン」が内蔵されています:
- Chrome / Edge: V8エンジン
- Firefox: SpiderMonkey
- Safari: JavaScriptCore
このエンジンがJavaScriptコードを読み取り、実行します。
ステップ3: JavaScriptコードの実行
// script.js
document.getElementById('btn').addEventListener('click', function() {
document.getElementById('title').textContent = 'クリックされました!';
});実行の流れ:
1. ブラウザがページを読み込み完了
↓
2. JavaScriptエンジンがscript.jsを読み込む
↓
3. コードを上から順に実行
↓
4. document.getElementById('btn') でボタン要素を取得
↓
5. addEventListener で「クリックされたら実行する関数」を登録
↓
6. ユーザーがボタンをクリックするのを待つ
↓
7. クリックされた!
↓
8. 登録した関数が実行される
↓
9. document.getElementById('title') でh1要素を取得
↓
10. textContent を変更
↓
11. ブラウザが画面を再描画
↓
12. 「こんにちは」→「クリックされました!」に変わる
DOM(Document Object Model)の正体:
DOMは、HTMLを「JavaScriptから操作できる形」に変換したものです。
視覚的な理解:
HTML(テキスト):
<div id="container">
<h1>タイトル</h1>
<p>段落</p>
</div>
↓ ブラウザが変換
DOM(オブジェクトの木構造):
document
|
html
|
body
|
div (id="container")
/ \
h1 p
| |
"タイトル" "段落"
DOMの各要素は「オブジェクト」:
// h1要素を取得
const title = document.querySelector('h1');
// このtitleは「オブジェクト」で、様々なプロパティとメソッドを持つ
console.log(title.textContent); // "タイトル"
console.log(title.id); // もしあれば id
console.log(title.className); // もしあれば class名
// メソッド(関数)も使える
title.addEventListener('click', function() {
console.log('クリックされた');
});なぜDOMが必要なのか:
HTMLはただのテキストファイルです。JavaScriptから直接は操作できません。
HTML (テキスト) → ❌ JavaScriptから直接操作できない
HTML → DOM (オブジェクト) → ✅ JavaScriptから操作できる
DOMを操作すると画面が変わる理由:
1. JavaScript で DOM を変更する
例: element.textContent = "新しいテキスト"
↓
2. ブラウザがDOMの変更を検知
↓
3. 「レンダーツリー」を再構築
↓
4. レイアウトを再計算
↓
5. 画面を再描画
↓
6. 目に見える変化が起こる
JavaScriptは「イベント駆動」で動きます。
イベント駆動とは:
従来のプログラム(順次実行):
1行目を実行 → 2行目を実行 → 3行目を実行 → 終了
イベント駆動プログラム:
1. 準備をする
2. イベントを待つ(クリック、入力、スクロールなど)
3. イベントが起こったら、対応する処理を実行
4. また待つ
具体例:
// 準備
const button = document.querySelector('#btn');
// イベントリスナーを登録(「こうなったら、これをして」と指示)
button.addEventListener('click', function() {
console.log('ボタンがクリックされました');
});
// ここでプログラムは終わらない
// ユーザーがボタンをクリックするのを「待ち続ける」イベントの例:
click: クリックされたinput: 入力があったsubmit: フォームが送信されたscroll: スクロールしたkeydown: キーボードが押されたload: ページの読み込みが完了した
イベントループ:
JavaScriptエンジンは「イベントループ」という仕組みで動いています:
while (true) { // 無限ループ
// イベントキューにイベントがあるか確認
if (イベントがある) {
// そのイベントの処理を実行
イベントハンドラを実行();
}
// なければ待つ
}
これにより、ページを開いている間ずっと、ユーザーの操作に反応できます。
これらの仕組みを理解すると:
1. エラーが理解できる
Uncaught TypeError: Cannot read property 'textContent' of null
→ document.querySelector() が null を返した
→ 要素が見つからなかった
→ HTMLの構造を確認しよう
2. パフォーマンスを改善できる
❌ 悪い例:
for (let i = 0; i < 1000; i++) {
document.getElementById('result').textContent = i;
// 1000回も画面を再描画!遅い!
}
✅ 良い例:
let result = '';
for (let i = 0; i < 1000; i++) {
result += i;
}
document.getElementById('result').textContent = result;
// 1回だけ再描画。速い!
3. 非同期処理が理解できる
// なぜこの順番で実行されるのか分かる
console.log('1');
setTimeout(function() {
console.log('2');
}, 0);
console.log('3');
// 結果: 1 → 3 → 2
// (イベントループの仕組みによる)
誕生: 1995年、ブレンダン・アイク氏が10日間で最初のバージョンを作成。当初は「ブラウザで簡単なことをするための言語」でした。
進化:
- 1990年代: 簡単な動的効果のみ
- 2000年代: Ajax(非同期通信)の登場で本格的なWebアプリが可能に
- 2010年代: Node.js登場でサーバーサイドでも使えるように
- 2015年: ES6(ES2015)で大幅にモダンに
- 現在: 世界で最も使われているプログラミング言語の一つ
JavaScriptができること(現在):
-
フロントエンド(ブラウザ):
- Webページの動的な操作
- ユーザーインターフェース
- アニメーション
- フォームバリデーション
-
バックエンド(サーバー):
- Node.jsを使ったサーバーアプリケーション
- API開発
- データベース操作
-
モバイルアプリ:
- React Native
- Ionic
-
デスクトップアプリ:
- Electron(VS Code もこれで作られている)
-
その他:
- ゲーム開発
- IoT(Internet of Things)
- 機械学習
JavaScriptは、Webページに動的な機能を追加するプログラミング言語です。
できること:
- ボタンクリックで要素を表示/非表示
- フォームの入力チェック
- アニメーション効果
- APIからデータ取得
// let: 再代入可能
let name = "太郎";
name = "花子"; // OK
// const: 再代入不可(推奨)
const age = 25;
// age = 26; // エラー
// var: 古い書き方(使わない)
var city = "Tokyo";ルール:
- 基本的に
constを使う - 再代入が必要な場合のみ
let varは使わない
// 文字列(String)
const message = "こんにちは";
const name = 'Next.js';
const template = `Hello ${name}`; // テンプレートリテラル
// 数値(Number)
const count = 42;
const price = 19.99;
// 真偽値(Boolean)
const isActive = true;
const isCompleted = false;
// 配列(Array)
const fruits = ["りんご", "バナナ", "オレンジ"];
console.log(fruits[0]); // "りんご"
// オブジェクト(Object)
const user = {
name: "太郎",
age: 25,
city: "Tokyo"
};
console.log(user.name); // "太郎"
// null と undefined
const empty = null;
const notDefined = undefined;// 算術演算子
const sum = 10 + 5; // 15
const diff = 10 - 5; // 5
const product = 10 * 5; // 50
const quotient = 10 / 5; // 2
const remainder = 10 % 3; // 1
// 比較演算子
10 === 10 // true(厳密等価)
10 !== 5 // true(厳密不等価)
10 > 5 // true
10 <= 10 // true
// 論理演算子
true && false // false(AND)
true || false // true(OR)
!true // false(NOT)const age = 20;
if (age >= 20) {
console.log("成人です");
} else if (age >= 13) {
console.log("ティーンです");
} else {
console.log("子供です");
}const status = age >= 20 ? "成人" : "未成年";const fruit = "apple";
switch (fruit) {
case "apple":
console.log("りんご");
break;
case "banana":
console.log("バナナ");
break;
default:
console.log("その他");
}// 基本的なforループ
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// 配列のループ
const fruits = ["りんご", "バナナ", "オレンジ"];
for (const fruit of fruits) {
console.log(fruit);
}
// forEach
fruits.forEach((fruit, index) => {
console.log(`${index}: ${fruit}`);
});// 関数宣言
function greet(name) {
return `こんにちは、${name}さん`;
}
console.log(greet("太郎")); // "こんにちは、太郎さん"
// 関数式
const add = function(a, b) {
return a + b;
};
// アロー関数(推奨)
const multiply = (a, b) => {
return a * b;
};
// 短縮形(1行の場合)
const double = (n) => n * 2;
const square = n => n * n; // 引数が1つの場合は()省略可const greet = (name = "ゲスト") => {
return `こんにちは、${name}さん`;
};
greet(); // "こんにちは、ゲストさん"
greet("太郎"); // "こんにちは、太郎さん"const numbers = [1, 2, 3, 4, 5];
// map: 各要素を変換
const doubled = numbers.map(n => n * 2);
// [2, 4, 6, 8, 10]
// filter: 条件に合う要素を抽出
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4]
// reduce: 集計
const sum = numbers.reduce((acc, n) => acc + n, 0);
// 15
// find: 最初に一致する要素
const found = numbers.find(n => n > 3);
// 4
// includes: 含まれているか
const hasThree = numbers.includes(3);
// true
// push / pop
numbers.push(6); // 末尾に追加
numbers.pop(); // 末尾を削除
// unshift / shift
numbers.unshift(0); // 先頭に追加
numbers.shift(); // 先頭を削除const user = {
name: "太郎",
age: 25,
city: "Tokyo"
};
// ドット記法
console.log(user.name); // "太郎"
// ブラケット記法
console.log(user["age"]); // 25
// 分割代入
const { name, age } = user;
console.log(name); // "太郎"const user = { name: "太郎", age: 25 };
const updatedUser = { ...user, city: "Tokyo" };
// { name: "太郎", age: 25, city: "Tokyo" }
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
// [1, 2, 3, 4, 5]// IDで取得
const element = document.getElementById("myId");
// クラス名で取得
const elements = document.getElementsByClassName("myClass");
// セレクタで取得(推奨)
const button = document.querySelector(".btn");
const buttons = document.querySelectorAll(".btn");// テキストの変更
element.textContent = "新しいテキスト";
// HTMLの変更
element.innerHTML = "<strong>太字</strong>";
// スタイルの変更
element.style.color = "red";
element.style.fontSize = "20px";
// クラスの追加・削除
element.classList.add("active");
element.classList.remove("inactive");
element.classList.toggle("visible");
// 属性の操作
element.setAttribute("data-id", "123");
const id = element.getAttribute("data-id");// 要素を作成
const newDiv = document.createElement("div");
newDiv.textContent = "新しい要素";
newDiv.classList.add("box");
// 要素を追加
const container = document.querySelector(".container");
container.appendChild(newDiv);
// 要素を削除
container.removeChild(newDiv);const button = document.querySelector("#myButton");
// クリックイベント
button.addEventListener("click", () => {
console.log("ボタンがクリックされました");
});
// イベントオブジェクト
button.addEventListener("click", (event) => {
console.log(event.target); // クリックされた要素
event.preventDefault(); // デフォルト動作を防ぐ
});// クリック
element.addEventListener("click", handler);
// マウスオーバー
element.addEventListener("mouseenter", handler);
element.addEventListener("mouseleave", handler);
// フォーム
form.addEventListener("submit", handler);
input.addEventListener("input", handler);
input.addEventListener("change", handler);
// キーボード
document.addEventListener("keydown", (e) => {
console.log(e.key); // 押されたキー
});Next.jsで作成します。
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div className="min-h-screen flex items-center justify-center bg-gray-100">
<div className="bg-white rounded-lg shadow-lg p-8 text-center">
<h1 className="text-3xl font-bold mb-8">カウンター</h1>
<div className="text-6xl font-bold mb-8 text-blue-600">
{count}
</div>
<div className="flex gap-4 justify-center">
<button
onClick={() => setCount(count - 1)}
className="px-6 py-3 bg-red-500 text-white rounded-lg hover:bg-red-600 transition"
>
-1
</button>
<button
onClick={() => setCount(0)}
className="px-6 py-3 bg-gray-500 text-white rounded-lg hover:bg-gray-600 transition"
>
リセット
</button>
<button
onClick={() => setCount(count + 1)}
className="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition"
>
+1
</button>
</div>
</div>
</div>
)
}📸 スクリーンショット: カウンターアプリの画面
'use client'
import { useState } from 'react'
export default function Toggle() {
const [isVisible, setIsVisible] = useState(true)
return (
<div className="min-h-screen flex items-center justify-center bg-gray-100">
<div className="bg-white rounded-lg shadow-lg p-8">
<button
onClick={() => setIsVisible(!isVisible)}
className="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 mb-4"
>
{isVisible ? "非表示" : "表示"}
</button>
{isVisible && (
<div className="p-4 bg-blue-50 rounded-lg">
<p className="text-gray-700">
これは表示/非表示を切り替えられるコンテンツです。
</p>
</div>
)}
</div>
</div>
)
}ボタンをクリックすると背景色が変わるアプリを作成してください。
要件:
- 3色以上のボタン
- クリックで背景色が変わる
解答例
'use client'
import { useState } from 'react'
export default function ColorChanger() {
const [bgColor, setBgColor] = useState('bg-white')
const colors = [
{ name: '赤', class: 'bg-red-100' },
{ name: '青', class: 'bg-blue-100' },
{ name: '緑', class: 'bg-green-100' },
{ name: '黄', class: 'bg-yellow-100' },
]
return (
<div className={`min-h-screen flex items-center justify-center ${bgColor} transition-colors duration-300`}>
<div className="bg-white rounded-lg shadow-lg p-8">
<h1 className="text-2xl font-bold mb-6">カラーチェンジャー</h1>
<div className="flex gap-3">
{colors.map((color) => (
<button
key={color.class}
onClick={() => setBgColor(color.class)}
className={`px-4 py-2 ${color.class} rounded-lg border-2 hover:scale-105 transition`}
>
{color.name}
</button>
))}
</div>
</div>
</div>
)
}テキストエリアに文字を入力すると、文字数がリアルタイムで表示されるアプリを作成してください。
解答例
'use client'
import { useState } from 'react'
export default function TextCounter() {
const [text, setText] = useState('')
return (
<div className="min-h-screen flex items-center justify-center bg-gray-100">
<div className="bg-white rounded-lg shadow-lg p-8 w-full max-w-md">
<h1 className="text-2xl font-bold mb-4">文字数カウンター</h1>
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
className="w-full h-32 p-3 border rounded-lg mb-4"
placeholder="テキストを入力してください"
/>
<div className="text-right text-lg">
<span className="font-bold text-blue-600">{text.length}</span>
<span className="text-gray-600"> 文字</span>
</div>
</div>
</div>
)
}原因: 存在しない要素にアクセスしている
解決策:
const element = document.querySelector("#myId");
if (element) {
element.textContent = "更新";
}原因: Next.jsでイベントハンドラを使う場合、クライアントコンポーネントにする必要がある
解決策:
ファイルの先頭に 'use client' を追加
原因: Reactの状態は直接変更できない
解決策:
// ❌ 間違い
count = count + 1;
// ✅ 正しい
setCount(count + 1);原因: 要素が存在する前にリスナーを設定
解決策:
Reactの場合は useEffect を使用
useEffect(() => {
const element = document.querySelector("#myId");
element?.addEventListener("click", handler);
return () => {
element?.removeEventListener("click", handler);
};
}, []);この章では以下のことを学びました:
- ✅ JavaScript基本文法(変数、データ型、演算子)
- ✅ 制御構文(if, for, switch)
- ✅ 関数(アロー関数、デフォルト引数)
- ✅ 配列とオブジェクトの操作
- ✅ DOM操作とイベント処理
- ✅ インタラクティブUIの作成
次の章では、TypeScriptを使った型安全な開発について学びます。
学習を完了したら、以下の項目をチェックしてください:
- JavaScriptエンジン(V8など)の役割を理解している
- DOMとは何か、なぜ必要なのかを説明できる
- イベント駆動プログラミングの概念を理解している
- 同期処理と非同期処理の違いを理解している
- イベントループの基本的な仕組みを理解している
- 変数の宣言(const, let, var)と使い分けができる
- 基本的なデータ型(string, number, boolean, null, undefined)を理解している
- 配列の基本操作(push, pop, map, filter)ができる
- オブジェクトの作成とプロパティアクセスができる
- 関数の定義と呼び出しができる
- アロー関数の書き方を理解している
-
document.querySelector()で要素を取得できる -
element.textContentでテキストを変更できる -
element.classList.add/remove()でクラスを操作できる -
element.styleでスタイルを変更できる - 新しい要素を作成して追加できる
-
addEventListener()でイベントリスナーを登録できる - クリックイベントを処理できる
- input/changeイベントを処理できる
- イベントオブジェクトの使い方を理解している
- ボタンクリックで画面の内容を変更できる
- フォーム入力を取得して処理できる
- カウンターアプリを作成できる
- ブラウザの開発者ツールでデバッグできる
- JavaScriptの型安全性の問題を理解している
- TypeScriptがなぜ必要なのかを理解している