Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

README.md

第3章: JavaScript基礎

学習目標

この章では、JavaScriptの基礎を学び、インタラクティブなUIを作成します。

  • JavaScriptがブラウザでどのように実行されるかを理解する
  • DOMとは何か、なぜ重要かを理解する
  • イベント駆動プログラミングの仕組みを理解する
  • JavaScriptの基本文法
  • 変数とデータ型
  • 関数と制御構文
  • DOM操作
  • イベント処理

成果物: 操作で変わるインタラクティブUI


0. JavaScriptがWebページを動的にする仕組み

0-1. なぜJavaScriptが必要なのか

HTMLとCSSだけではできないこと:

<!-- HTMLとCSSだけ = 静的(変化しない) -->
<button>クリックしてください</button>

これをクリックしても、何も起こりません。

JavaScriptを加えると = 動的(変化する):

<button onclick="alert('クリックされました!')">クリックしてください</button>

クリックすると、アラートが表示されます。

3つの技術の役割を車に例えると:

HTML     = 車の骨組み(フレーム、座席、ハンドルなど)
CSS      = 車の外装(色、デザイン)
JavaScript = エンジンと電子制御(動く仕組み)

0-2. 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. 「こんにちは」→「クリックされました!」に変わる

0-3. DOMとは何か - 最も重要な概念

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. 目に見える変化が起こる

0-4. イベント駆動プログラミング

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 (イベントがある) {
    // そのイベントの処理を実行
    イベントハンドラを実行();
  }
  // なければ待つ
}

これにより、ページを開いている間ずっと、ユーザーの操作に反応できます。

0-5. なぜこの理解が重要なのか

これらの仕組みを理解すると:

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
// (イベントループの仕組みによる)

1. JavaScriptとは

1-0. JavaScriptの歴史と現在

誕生: 1995年、ブレンダン・アイク氏が10日間で最初のバージョンを作成。当初は「ブラウザで簡単なことをするための言語」でした。

進化:

  • 1990年代: 簡単な動的効果のみ
  • 2000年代: Ajax(非同期通信)の登場で本格的なWebアプリが可能に
  • 2010年代: Node.js登場でサーバーサイドでも使えるように
  • 2015年: ES6(ES2015)で大幅にモダンに
  • 現在: 世界で最も使われているプログラミング言語の一つ

JavaScriptができること(現在):

  1. フロントエンド(ブラウザ):

    • Webページの動的な操作
    • ユーザーインターフェース
    • アニメーション
    • フォームバリデーション
  2. バックエンド(サーバー):

    • Node.jsを使ったサーバーアプリケーション
    • API開発
    • データベース操作
  3. モバイルアプリ:

    • React Native
    • Ionic
  4. デスクトップアプリ:

    • Electron(VS Code もこれで作られている)
  5. その他:

    • ゲーム開発
    • IoT(Internet of Things)
    • 機械学習

JavaScriptは、Webページに動的な機能を追加するプログラミング言語です。

できること:

  • ボタンクリックで要素を表示/非表示
  • フォームの入力チェック
  • アニメーション効果
  • APIからデータ取得

2. 基本文法

2-1. 変数の宣言

// let: 再代入可能
let name = "太郎";
name = "花子"; // OK

// const: 再代入不可(推奨)
const age = 25;
// age = 26; // エラー

// var: 古い書き方(使わない)
var city = "Tokyo";

ルール:

  • 基本的に const を使う
  • 再代入が必要な場合のみ let
  • var は使わない

2-2. データ型

// 文字列(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;

2-3. 演算子

// 算術演算子
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)

3. 制御構文

3-1. 条件分岐(if文)

const age = 20;

if (age >= 20) {
  console.log("成人です");
} else if (age >= 13) {
  console.log("ティーンです");
} else {
  console.log("子供です");
}

3-2. 三項演算子

const status = age >= 20 ? "成人" : "未成年";

3-3. switch文

const fruit = "apple";

switch (fruit) {
  case "apple":
    console.log("りんご");
    break;
  case "banana":
    console.log("バナナ");
    break;
  default:
    console.log("その他");
}

3-4. ループ(for文)

// 基本的な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}`);
});

4. 関数

4-1. 関数の定義

// 関数宣言
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つの場合は()省略可

4-2. デフォルト引数

const greet = (name = "ゲスト") => {
  return `こんにちは、${name}さん`;
};

greet();       // "こんにちは、ゲストさん"
greet("太郎"); // "こんにちは、太郎さん"

5. 配列の操作

5-1. よく使うメソッド

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();    // 先頭を削除

6. オブジェクトの操作

6-1. プロパティのアクセス

const user = {
  name: "太郎",
  age: 25,
  city: "Tokyo"
};

// ドット記法
console.log(user.name); // "太郎"

// ブラケット記法
console.log(user["age"]); // 25

// 分割代入
const { name, age } = user;
console.log(name); // "太郎"

6-2. スプレッド演算子

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]

7. DOM操作

7-1. 要素の取得

// IDで取得
const element = document.getElementById("myId");

// クラス名で取得
const elements = document.getElementsByClassName("myClass");

// セレクタで取得(推奨)
const button = document.querySelector(".btn");
const buttons = document.querySelectorAll(".btn");

7-2. 要素の操作

// テキストの変更
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");

7-3. 要素の作成と追加

// 要素を作成
const newDiv = document.createElement("div");
newDiv.textContent = "新しい要素";
newDiv.classList.add("box");

// 要素を追加
const container = document.querySelector(".container");
container.appendChild(newDiv);

// 要素を削除
container.removeChild(newDiv);

8. イベント処理

8-1. イベントリスナー

const button = document.querySelector("#myButton");

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

// イベントオブジェクト
button.addEventListener("click", (event) => {
  console.log(event.target); // クリックされた要素
  event.preventDefault();    // デフォルト動作を防ぐ
});

8-2. よく使うイベント

// クリック
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); // 押されたキー
});

9. インタラクティブUIを作ろう

9-1. カウンターアプリ

Next.jsで作成します。

src/app/page.tsx

'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>
  )
}

📸 スクリーンショット: カウンターアプリの画面

9-2. トグル表示

'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>
  )
}

ミニ課題

課題1: カラーチェンジャー

ボタンをクリックすると背景色が変わるアプリを作成してください。

要件:

  • 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>
  )
}

課題2: 入力カウンター

テキストエリアに文字を入力すると、文字数がリアルタイムで表示されるアプリを作成してください。

解答例
'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>
  )
}

よくあるエラーと解決策

エラー1: Uncaught TypeError: Cannot read property

原因: 存在しない要素にアクセスしている

解決策:

const element = document.querySelector("#myId");
if (element) {
  element.textContent = "更新";
}

エラー2: 'use client' directive must be used

原因: Next.jsでイベントハンドラを使う場合、クライアントコンポーネントにする必要がある

解決策: ファイルの先頭に 'use client' を追加

エラー3: State更新が反映されない

原因: Reactの状態は直接変更できない

解決策:

// ❌ 間違い
count = count + 1;

// ✅ 正しい
setCount(count + 1);

エラー4: イベントリスナーが動作しない

原因: 要素が存在する前にリスナーを設定

解決策: 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とは何か、なぜ必要なのかを説明できる
  • イベント駆動プログラミングの概念を理解している
  • 同期処理と非同期処理の違いを理解している
  • イベントループの基本的な仕組みを理解している

JavaScript 基本文法

  • 変数の宣言(const, let, var)と使い分けができる
  • 基本的なデータ型(string, number, boolean, null, undefined)を理解している
  • 配列の基本操作(push, pop, map, filter)ができる
  • オブジェクトの作成とプロパティアクセスができる
  • 関数の定義と呼び出しができる
  • アロー関数の書き方を理解している

DOM操作

  • document.querySelector()で要素を取得できる
  • element.textContentでテキストを変更できる
  • element.classList.add/remove()でクラスを操作できる
  • element.styleでスタイルを変更できる
  • 新しい要素を作成して追加できる

イベント処理

  • addEventListener()でイベントリスナーを登録できる
  • クリックイベントを処理できる
  • input/changeイベントを処理できる
  • イベントオブジェクトの使い方を理解している

実践スキル

  • ボタンクリックで画面の内容を変更できる
  • フォーム入力を取得して処理できる
  • カウンターアプリを作成できる
  • ブラウザの開発者ツールでデバッグできる

次のステップへの準備

  • JavaScriptの型安全性の問題を理解している
  • TypeScriptがなぜ必要なのかを理解している

参考リンク