JavaScript学習ガイド【初心者〜中級者対応】〜Mathオブジェクトとグローバルオブジェクトの理解を中心に〜

## はじめに

この記事は、**JavaScript初心者から中級者を対象**とした体系的な学習ガイドです。特に `Math` オブジェクトや `グローバルオブジェクト` など、**JavaScriptの全体像を構造的に理解すること**に重点を置いており、教材や研修カリキュラムにも応用可能な内容となっています。

## 📚 学習の進め方

1. **基礎概念の理解** → JavaScript の特徴と動作環境
2. **オブジェクト体系の把握** → グローバルオブジェクトとビルトインオブジェクト
3. **実践的な使い方** → Mathオブジェクトの活用法
4. **応用技術** → DOM操作とイベント処理

---

## 1. JavaScript の特徴と実行環境

### JavaScript とは何か？

JavaScriptは、**Webページに動きを与えるプログラミング言語**です。ブラウザ上で動作し、HTMLやCSSと組み合わせることで、インタラクティブなWebサイトを作ることができます。

### 主な特徴

| 項目 | 内容 | 詳細説明 |
|------|------|----------|
| **クライアントサイド言語** | 主にブラウザで動作 | Chrome、Firefox、Safari、Edgeなどのブラウザ内で実行される |
| **インタプリタ型** | 実行時に逐次解釈 | コンパイル不要で、書いたコードがそのまま実行される |
| **実行環境** | 複数の環境で動作可能 | ブラウザ：`window`、Node.js：`global`、共通：`globalThis` |
| **HTML/CSSとの連携** | DOM操作で動的なUI制御 | ページの内容を動的に変更、アニメーション効果など |

### 実行環境の違い

```javascript
// ブラウザ環境
console.log(window); // ブラウザのWindowオブジェクト

// Node.js環境
console.log(global); // Node.jsのglobalオブジェクト

// どちらでも使える共通オブジェクト
console.log(globalThis); // ES2020で追加された統一オブジェクト
```

---

## 2. グローバルオブジェクトとビルトインオブジェクト

### グローバルオブジェクトとは？

**どこからでもアクセスできる特別なオブジェクト**のことです。JavaScriptプログラムの「大元」となる存在で、すべての変数や関数の最上位に位置します。

### ビルトインオブジェクト（組み込みオブジェクト）とは？

JavaScriptに**最初から備わっている便利な道具箱**のことです。これらは特別な設定や読み込みをしなくても、すぐに使うことができます。

| 種類 | 説明 | 代表的な例 |
|------|------|------------|
| **グローバルオブジェクト** | どこからでもアクセス可能な最上位オブジェクト | `window`（ブラウザ）、`global`（Node.js）、`globalThis`（共通） |
| **ビルトインオブジェクト** | 最初から使える便利な機能集 | `Math`, `Array`, `Date`, `JSON`, `RegExp`, `Object`, `String`, `Number` |
| **Mathオブジェクト** | 数学的処理に特化したビルトインオブジェクト | 数値計算、乱数生成、三角関数など |

### ビルトインオブジェクトの分類

```javascript
// 数値・計算系
Math.random();    // Math オブジェクト
Number.parseInt(); // Number オブジェクト

// 文字列系
String.prototype.toUpperCase(); // String オブジェクト

// 日付・時刻系
new Date(); // Date オブジェクト

// 配列・オブジェクト系
Array.from(); // Array オブジェクト
Object.keys(); // Object オブジェクト

// データ変換系
JSON.stringify(); // JSON オブジェクト

// 正規表現系
new RegExp(); // RegExp オブジェクト
```

---

## 3. Mathオブジェクトの基礎と実践活用

### Math オブジェクトとは？

JavaScriptに標準搭載された**数学用の関数とプロパティの集合体**です。`Math.random()` のように、オブジェクト名に続けてメソッド名を書くことで使用できます。

### 重要なポイント

- **インスタンス化不要**：`new Math()` とは書かない
- **静的メソッド**：すべてのメソッドは `Math.メソッド名()` で呼び出す
- **グローバル利用可能**：どこからでも使える

### 基本的なメソッド一覧

#### 乱数・切り捨て・切り上げ・四捨五入

| メソッド | 説明 | 例 | 結果 |
|----------|------|----|----- |
| `Math.random()` | 0以上1未満の乱数を生成 | `Math.random()` | `0.7834592834` |
| `Math.floor(x)` | 小数点以下を切り捨て | `Math.floor(4.7)` | `4` |
| `Math.ceil(x)` | 小数点以下を切り上げ | `Math.ceil(4.1)` | `5` |
| `Math.round(x)` | 四捨五入 | `Math.round(4.5)` | `5` |

#### 数値操作

| メソッド | 説明 | 例 | 結果 |
|----------|------|----|----- |
| `Math.abs(x)` | 絶対値を返す | `Math.abs(-5)` | `5` |
| `Math.pow(x, y)` | xのy乗を計算 | `Math.pow(2, 3)` | `8` |
| `Math.sqrt(x)` | 平方根を計算 | `Math.sqrt(25)` | `5` |
| `Math.max(...args)` | 引数の中の最大値 | `Math.max(1, 9, 3)` | `9` |
| `Math.min(...args)` | 引数の中の最小値 | `Math.min(1, 9, 3)` | `1` |

#### 定数

| プロパティ | 説明 | 値 |
|------------|------|-----|
| `Math.PI` | 円周率 | `3.141592653589793` |
| `Math.E` | 自然対数の底 | `2.718281828459045` |

### 実践的な使用例

#### 1. 指定範囲の整数乱数を生成

```javascript
// 1〜10の整数乱数を生成する関数
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

console.log(getRandomInt(1, 10)); // 1〜10のどれか
console.log(getRandomInt(1, 10)); // 1〜10のどれか（毎回異なる）
```

#### 2. 配列からランダムに要素を選択

```javascript
const colors = ['red', 'blue', 'green', 'yellow', 'purple'];

function getRandomColor() {
  const randomIndex = Math.floor(Math.random() * colors.length);
  return colors[randomIndex];
}

console.log(getRandomColor()); // 'blue' や 'green' など
```

#### 3. 数値の小数点以下を操作

```javascript
const price = 1234.5678;

console.log('切り捨て:', Math.floor(price));   // 1234
console.log('切り上げ:', Math.ceil(price));    // 1235
console.log('四捨五入:', Math.round(price));   // 1235

// 小数点第2位まで表示（四捨五入）
console.log('価格:', Math.round(price * 100) / 100); // 1234.57
```

#### 4. 距離の計算（2点間の直線距離）

```javascript
function getDistance(x1, y1, x2, y2) {
  const dx = x2 - x1;
  const dy = y2 - y1;
  return Math.sqrt(dx * dx + dy * dy);
}

console.log(getDistance(0, 0, 3, 4)); // 5（3-4-5の直角三角形）
```

---

## 4. データ型と変数の理解

### データ型の分類

JavaScriptのデータ型は、大きく**プリミティブ型**と**参照型**に分かれます。

#### プリミティブ型（基本データ型）

| 型名 | 説明 | 例 |
|------|------|----|
| `string` | 文字列 | `"Hello"`, `'World'`, `` `テンプレート` `` |
| `number` | 数値 | `42`, `3.14`, `Infinity`, `NaN` |
| `boolean` | 真偽値 | `true`, `false` |
| `undefined` | 未定義 | `undefined` |
| `null` | 意図的な空値 | `null` |
| `bigint` | 大きな整数 | `9007199254740991n` |
| `symbol` | 一意の識別子 | `Symbol('id')` |

#### 参照型（オブジェクト型）

| 型名 | 説明 | 例 |
|------|------|----|
| `object` | オブジェクト | `{ name: 'Taro', age: 30 }` |
| `array` | 配列 | `[1, 2, 3]`, `['a', 'b', 'c']` |
| `function` | 関数 | `function() {}`, `() => {}` |
| `date` | 日付 | `new Date()` |

### 変数宣言の方法

```javascript
// const: 再代入不可（推奨）
const name = 'Taro';
const age = 30;

// let: 再代入可能
let score = 100;
score = 95; // OK

// var: 非推奨（巻き上げの問題あり）
var oldStyle = 'avoid using var';
```

### 型確認の方法

```javascript
console.log(typeof "Hello");      // "string"
console.log(typeof 42);           // "number"
console.log(typeof true);         // "boolean"
console.log(typeof undefined);    // "undefined"
console.log(typeof null);         // "object" (JavaScriptの歴史的な仕様)
console.log(typeof {});           // "object"
console.log(typeof []);           // "object" (配列もオブジェクトの一種)
console.log(typeof function(){}); // "function"
```

---

## 5. 関数の定義と使い方

### 関数定義の方法

#### 1. 通常の関数宣言

```javascript
function greet(name) {
  return `Hello, ${name}!`;
}

console.log(greet('Taro')); // "Hello, Taro!"
```

#### 2. 関数式

```javascript
const greet = function(name) {
  return `Hello, ${name}!`;
};

console.log(greet('Hanako')); // "Hello, Hanako!"
```

#### 3. アロー関数（ES6以降）

```javascript
// 基本形
const greet = (name) => {
  return `Hello, ${name}!`;
};

// 省略形（戻り値が1行の場合）
const greet = name => `Hello, ${name}!`;

// 引数が複数の場合
const add = (a, b) => a + b;

console.log(add(3, 5)); // 8
```

#### 4. 即座実行関数（IIFE）

```javascript
(function() {
  console.log('即座に実行される！');
})();

// アロー関数版
(() => {
  console.log('アロー関数でも即座実行！');
})();
```

### コールバック関数の理解

```javascript
// 配列の各要素に対して処理を実行
const numbers = [1, 2, 3, 4, 5];

// forEach: 各要素に対して処理実行
numbers.forEach(num => console.log(num * 2));

// map: 各要素を変換して新しい配列を作成
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// filter: 条件に合う要素だけを抽出
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4]
```

---

## 6. 制御構文の活用

### 条件分岐

#### if文

```javascript
const score = 85;

if (score >= 90) {
  console.log('優秀');
} else if (score >= 70) {
  console.log('良好');
} else if (score >= 60) {
  console.log('合格');
} else {
  console.log('不合格');
}
```

#### switch文

```javascript
const day = '月曜日';

switch (day) {
  case '月曜日':
    console.log('新しい週の始まり');
    break;
  case '金曜日':
    console.log('週末が近い');
    break;
  case '土曜日':
  case '日曜日':
    console.log('休日');
    break;
  default:
    console.log('平日');
}
```

### 繰り返し処理

#### for文

```javascript
// 基本のfor文
for (let i = 0; i < 5; i++) {
  console.log(`${i}回目の繰り返し`);
}

// 配列のfor文
const fruits = ['apple', 'banana', 'orange'];
for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

// for...of文（値を取得）
for (const fruit of fruits) {
  console.log(fruit);
}

// for...in文（キーを取得）
const person = { name: 'Taro', age: 30, city: 'Tokyo' };
for (const key in person) {
  console.log(`${key}: ${person[key]}`);
}
```

#### while文とdo-while文

```javascript
// while文
let count = 0;
while (count < 3) {
  console.log(`Count: ${count}`);
  count++;
}

// do-while文（最低1回は実行される）
let num = 0;
do {
  console.log(`Number: ${num}`);
  num++;
} while (num < 3);
```

---

## 7. 配列とオブジェクトの操作

### 配列（Array）の基本操作

```javascript
// 配列の作成
const fruits = ['apple', 'banana', 'orange'];
const numbers = [1, 2, 3, 4, 5];

// 要素の追加・削除
fruits.push('grape');        // 末尾に追加
fruits.unshift('mango');     // 先頭に追加
fruits.pop();                // 末尾を削除
fruits.shift();              // 先頭を削除

console.log(fruits); // ['apple', 'banana', 'orange']

// 要素の検索
console.log(fruits.indexOf('banana'));    // 1
console.log(fruits.includes('apple'));    // true

// 配列の結合・分割
const newFruits = fruits.concat(['kiwi', 'peach']);
const sliced = fruits.slice(1, 3); // インデックス1から3未満

console.log(newFruits); // ['apple', 'banana', 'orange', 'kiwi', 'peach']
console.log(sliced);    // ['banana', 'orange']
```

### 配列の高度なメソッド

```javascript
const numbers = [1, 2, 3, 4, 5];

// map: 各要素を変換
const squared = numbers.map(num => num * num);
console.log(squared); // [1, 4, 9, 16, 25]

// filter: 条件に合う要素を抽出
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4]

// reduce: 配列を1つの値に集約
const sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 15

// find: 条件に合う最初の要素を取得
const found = numbers.find(num => num > 3);
console.log(found); // 4

// some: 条件に合う要素が1つでもあるか
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true

// every: すべての要素が条件に合うか
const allPositive = numbers.every(num => num > 0);
console.log(allPositive); // true
```

### オブジェクト（Object）の操作

```javascript
// オブジェクトの作成
const person = {
  name: 'Taro',
  age: 30,
  city: 'Tokyo',
  hobbies: ['reading', 'swimming']
};

// プロパティへのアクセス
console.log(person.name);       // 'Taro'
console.log(person['age']);     // 30

// プロパティの追加・変更・削除
person.job = 'Engineer';        // 追加
person.age = 31;                // 変更
delete person.city;             // 削除

// オブジェクトのキー・値・エントリを取得
console.log(Object.keys(person));    // ['name', 'age', 'hobbies', 'job']
console.log(Object.values(person));  // ['Taro', 31, ['reading', 'swimming'], 'Engineer']
console.log(Object.entries(person)); // [['name', 'Taro'], ['age', 31], ...]

// オブジェクトのコピー
const personCopy = { ...person }; // スプレッド演算子（浅いコピー）
const personCopy2 = Object.assign({}, person); // Object.assign（浅いコピー）
```

---

## 8. DOM操作とイベント処理

### DOM（Document Object Model）とは？

HTML文書をJavaScriptから操作するための仕組みです。WebページのHTML要素を取得・変更・追加・削除できます。

### 基本的なDOM操作

#### HTML要素の取得

```javascript
// IDで取得
const button = document.getElementById('myButton');

// クラス名で取得（最初の1つ）
const item = document.querySelector('.item');

// クラス名で取得（すべて）
const items = document.querySelectorAll('.item');

// タグ名で取得
const paragraphs = document.getElementsByTagName('p');
```

#### 要素の内容を変更

```javascript
// テキスト内容を変更
const heading = document.getElementById('title');
heading.textContent = '新しいタイトル';

// HTML内容を変更
const container = document.getElementById('container');
container.innerHTML = '<p>新しい段落</p>';

// 属性を変更
const image = document.querySelector('img');
image.src = 'new-image.jpg';
image.alt = '新しい画像';
```

#### CSSスタイルとクラスの操作

```javascript
const element = document.querySelector('.box');

// スタイルの直接変更
element.style.backgroundColor = 'red';
element.style.width = '200px';
element.style.height = '100px';

// クラスの追加・削除・切り替え
element.classList.add('active');
element.classList.remove('hidden');
element.classList.toggle('highlight');

// クラスの存在確認
if (element.classList.contains('active')) {
  console.log('activeクラスが付いています');
}
```

### イベント処理

#### 基本的なイベントリスナー

```javascript
const button = document.getElementById('clickButton');

// クリックイベント
button.addEventListener('click', function() {
  alert('ボタンがクリックされました！');
});

// アロー関数版
button.addEventListener('click', () => {
  console.log('クリックされました');
});

// 複数のイベントを処理
button.addEventListener('mouseenter', () => {
  button.style.backgroundColor = 'lightblue';
});

button.addEventListener('mouseleave', () => {
  button.style.backgroundColor = '';
});
```

#### フォームのイベント処理

```javascript
const form = document.getElementById('myForm');
const input = document.getElementById('textInput');

// フォーム送信イベント
form.addEventListener('submit', (event) => {
  event.preventDefault(); // デフォルトの送信動作を防ぐ
  
  const inputValue = input.value;
  if (inputValue.trim() === '') {
    alert('入力してください');
    return;
  }
  
  console.log('入力値:', inputValue);
});

// 入力値の変更イベント
input.addEventListener('input', (event) => {
  console.log('現在の入力値:', event.target.value);
});
```

#### 実践的な例：ToDoリスト

```javascript
const todoForm = document.getElementById('todoForm');
const todoInput = document.getElementById('todoInput');
const todoList = document.getElementById('todoList');

todoForm.addEventListener('submit', (event) => {
  event.preventDefault();
  
  const todoText = todoInput.value.trim();
  if (todoText === '') return;
  
  // 新しいリストアイテムを作成
  const listItem = document.createElement('li');
  listItem.textContent = todoText;
  
  // 削除ボタンを作成
  const deleteButton = document.createElement('button');
  deleteButton.textContent = '削除';
  deleteButton.addEventListener('click', () => {
    listItem.remove();
  });
  
  listItem.appendChild(deleteButton);
  todoList.appendChild(listItem);
  
  // 入力フィールドをクリア
  todoInput.value = '';
});
```

---

## 9. 非同期処理の基礎

### setTimeout と setInterval

```javascript
// 3秒後に実行
setTimeout(() => {
  console.log('3秒経過しました');
}, 3000);

// 1秒ごとに実行
const intervalId = setInterval(() => {
  console.log('1秒ごとに実行');
}, 1000);

// 5秒後に繰り返し処理を停止
setTimeout(() => {
  clearInterval(intervalId);
  console.log('繰り返し処理を停止');
}, 5000);
```

### Promise の基本

```javascript
// Promiseの作成
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = Math.random() > 0.5;
      if (success) {
        resolve('データの取得に成功');
      } else {
        reject('データの取得に失敗');
      }
    }, 2000);
  });
};

// Promiseの使用
fetchData()
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error(error);
  });
```

### async/await の使用

```javascript
// async関数の定義
async function getData() {
  try {
    const result = await fetchData();
    console.log(result);
  } catch (error) {
    console.error(error);
  }
}

// 実行
getData();
```

---

## 10. エラーハンドリングとデバッグ

### try-catch文

```javascript
function divideNumbers(a, b) {
  try {
    if (b === 0) {
      throw new Error('0で割ることはできません');
    }
    return a / b;
  } catch (error) {
    console.error('エラーが発生しました:', error.message);
    return null;
  } finally {
    console.log('処理が完了しました');
  }
}

console.log(divideNumbers(10, 2)); // 5
console.log(divideNumbers(10, 0)); // null（エラーメッセージも表示）
```

### デバッグのテクニック

```javascript
// console.log の活用
console.log('変数の値:', variable);
console.warn('警告メッセージ');
console.error('エラーメッセージ');

// オブジェクトの詳細表示
const obj = { name: 'Taro', age: 30 };
console.table(obj);

// 処理時間の測定
console.time('処理時間');
// 何らかの処理
console.timeEnd('処理時間');

// デバッガーの使用
debugger; // ブラウザの開発者ツールでここで停止
```

---

## 11. ES6以降のモダンJavaScript

### 分割代入（Destructuring）

```javascript
// 配列の分割代入
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first);  // 1
console.log(second); // 2
console.log(rest);   // [3, 4, 5]

// オブジェクトの分割代入
const person = { name: 'Taro', age: 30, city: 'Tokyo' };
const { name, age } = person;
console.log(name); // 'Taro'
console.log(age);  // 30

// 別名での取得
const { name: personName, city: location } = person;
console.log(personName); // 'Taro'
console.log(location);   // 'Tokyo'
```

### スプレッド演算子（...）

```javascript
// 配列の展開
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// オブジェクトの展開
const person1 = { name: 'Taro', age: 30 };
const person2 = { ...person1, city: 'Tokyo' }; // { name: 'Taro', age: 30, city: 'Tokyo' }

// 関数の引数として使用
function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
```

### テンプレートリテラル

```javascript
const name = 'Taro';
const age = 30;

// 従来の方法
const message1 = 'こんにちは、' + name + 'さん。あなたは' + age + '歳ですね。';

// テンプレートリテラル
const message2 = `こんにちは、${name}さん。あなたは${age}歳ですね。`;

// 複数行の文字列
const multiLine = `
  これは
  複数行の
  文字列です
`;
```

---

## 12. 実践演習問題

### 初級問題

#### 問題1: 基本的な計算機

```javascript
// 以下の関数を完成させてください
function calculator(a, b, operation) {
  // operation は '+', '-', '*', '/' のいずれか
  // 結果を返してください
}

// テスト
console.log(calculator(10, 5, '+')); // 15
console.log(calculator(10, 5, '-')); // 5
console.log(calculator(10, 5, '*')); // 50
console.log(calculator(10, 5, '/')); // 2
```

#### 解答例

```javascript
function calculator(a, b, operation) {
  switch (operation) {
    case '+':
      return a + b;
    case '-':
      return a - b;
    case '*':
      return a * b;
    case '/':
      return b !== 0 ? a / b : 'エラー: 0で割ることはできません';
    default:
      return 'エラー: 無効な演算子です';
  }
}
```

### 中級問題

#### 問題2: 配列の統計情報

```javascript
// 数値配列から平均値、最大値、最小値を求める関数
function getArrayStats(numbers) {
  // 平均値、最大値、最小値を含むオブジェクトを返してください
  // 例: { average: 3, max: 5, min: 1 }
}

// テスト
console.log(getArrayStats([1, 2, 3, 4, 5])); 
// { average: 3, max: 5, min: 1 }
```

#### 解答例

```javascript
function getArrayStats(numbers) {
  if (numbers.length === 0) {
    return { average: 0, max: 0, min: 0 };
  }
  
  const sum = numbers.reduce((total, num) => total + num, 0);
  const average = sum / numbers.length;
  const max = Math.max(...numbers);
  const min = Math.min(...numbers);
  
  return { average, max, min };
}
```

#### 問題3: DOM操作でカウンター作成

```html
<!-- HTML -->
<div id="counter">
  <h2 id="count">0</h2>
  <button id="increment">+1</button>
  <button id="decrement">-1</button>
  <button id="reset">リセット</button>
</div>
```

```javascript
// JavaScript: カウンターアプリを作成してください
// +1ボタンで数値を増加、-1ボタンで減少、リセットボタンで0に戻す
```

#### 解答例

```javascript
// DOM要素の取得
const countElement = document.getElementById('count');
const incrementButton = document.getElementById('increment');
const decrementButton = document.getElementById('decrement');
const resetButton = document.getElementById('reset');

// カウンターの初期値
let count = 0;

// カウンターを更新する関数
function updateCounter() {
  countElement.textContent = count;
}

// イベントリスナーの設定
incrementButton.addEventListener('click', () => {
  count++;
  updateCounter();
});

decrementButton.addEventListener('click', () => {
  count--;
  updateCounter();
});

resetButton.addEventListener('click', () => {
  count = 0;
  updateCounter();
});
```

### 上級問題

#### 問題4: 非同期処理でデータ取得シミュレーション

```javascript
// ユーザー情報を取得する非同期関数を作成してください
// ランダムに成功/失敗を判定し、適切に処理してください
async function fetchUserData(userId) {
  // 1-3秒のランダムな遅延後に結果を返す
  // 70%の確率で成功、30%の確率で失敗
  // 成功時: { id: userId, name: 'User' + userId, email: 'user' + userId + '@example.com' }
  // 失敗時: エラーをthrow
}

// 使用例
fetchUserData(1)
  .then(user => console.log('ユーザー情報:', user))
  .catch(error => console.error('エラー:', error));
```

#### 解答例

```javascript
function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    // 1-3秒のランダムな遅延
    const delay = Math.random() * 2000 + 1000;
    
    setTimeout(() => {
      // 70%の確率で成功
      const isSuccess = Math.random() > 0.3;
      
      if (isSuccess) {
        const userData = {
          id: userId,
          name: `User${userId}`,
          email: `user${userId}@example.com`
        };
        resolve(userData);
      } else {
        reject(new Error(`ユーザーID ${userId} の取得に失敗しました`));
      }
    }, delay);
  });
}

// async/await版の使用例
async function getUserInfo(userId) {
  try {
    console.log('ユーザー情報を取得中...');
    const user = await fetchUserData(userId);
    console.log('ユーザー情報:', user);
    return user;
  } catch (error) {
    console.error('エラー:', error.message);
    return null;
  }
}

// 実行
getUserInfo(1);
```

---

## 13. よくあるエラーと解決方法

### 構文エラー（Syntax Error）

```javascript
// ❌ 間違い: セミコロンやカンマの不備
const fruits = ['apple' 'banana', 'orange'];

// ✅ 正しい
const fruits = ['apple', 'banana', 'orange'];

// ❌ 間違い: 括弧の不一致
function greet(name {
  return `Hello, ${name}!`;
}

// ✅ 正しい
function greet(name) {
  return `Hello, ${name}!`;
}
```

### 参照エラー（Reference Error）

```javascript
// ❌ 間違い: 未定義の変数を使用
console.log(unknownVariable);

// ✅ 正しい: 変数を定義してから使用
const knownVariable = 'Hello';
console.log(knownVariable);

// ❌ 間違い: 存在しない関数を呼び出し
unknownFunction();

// ✅ 正しい: 関数を定義してから呼び出し
function knownFunction() {
  console.log('Function called');
}
knownFunction();
```

### 型エラー（Type Error）

```javascript
// ❌ 間違い: nullやundefinedのプロパティにアクセス
const user = null;
console.log(user.name); // TypeError

// ✅ 正しい: 存在確認してからアクセス
const user = null;
if (user && user.name) {
  console.log(user.name);
}

// または Optional Chaining（ES2020以降）
console.log(user?.name); // undefined（エラーにならない）
```

### よくある論理エラーと対策

```javascript
// ❌ 間違い: 配列の境界を超えたアクセス
const numbers = [1, 2, 3];
console.log(numbers[5]); // undefined

// ✅ 正しい: 境界チェック
if (index >= 0 && index < numbers.length) {
  console.log(numbers[index]);
}

// ❌ 間違い: == と === の混同
if (0 == false) {  // true（型変換が発生）
  console.log('予期しない動作');
}

// ✅ 正しい: 厳密等価演算子の使用
if (0 === false) { // false
  console.log('実行されない');
}
```

---

## 14. パフォーマンスとベストプラクティス

### 効率的なコードの書き方

#### DOM操作の最適化

```javascript
// ❌ 非効率: 何度もDOM操作
const list = document.getElementById('list');
for (let i = 0; i < 1000; i++) {
  const item = document.createElement('li');
  item.textContent = `Item ${i}`;
  list.appendChild(item); // 1000回のDOM操作
}

// ✅ 効率的: DocumentFragmentを使用
const list = document.getElementById('list');
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  const item = document.createElement('li');
  item.textContent = `Item ${i}`;
  fragment.appendChild(item);
}
list.appendChild(fragment); // 1回のDOM操作
```

#### 配列操作の最適化

```javascript
// ❌ 非効率: forEachで副作用
const numbers = [1, 2, 3, 4, 5];
const doubled = [];
numbers.forEach(num => {
  doubled.push(num * 2);
});

// ✅ 効率的: mapを使用
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(num => num * 2);
```

### メモリリークの防止

```javascript
// イベントリスナーの適切な削除
const button = document.getElementById('myButton');

function handleClick() {
  console.log('Clicked');
}

// イベントリスナーを追加
button.addEventListener('click', handleClick);

// 不要になったら削除
button.removeEventListener('click', handleClick);

// setIntervalの適切な停止
const intervalId = setInterval(() => {
  console.log('定期実行');
}, 1000);

// 不要になったら停止
clearInterval(intervalId);
```

---

## 15. 実際の開発でよく使う実用的なサンプル

### 1. フォームバリデーション

```javascript
class FormValidator {
  constructor(formElement) {
    this.form = formElement;
    this.errors = {};
    this.init();
  }
  
  init() {
    this.form.addEventListener('submit', (e) => {
      e.preventDefault();
      if (this.validate()) {
        this.onSuccess();
      } else {
        this.displayErrors();
      }
    });
  }
  
  validate() {
    this.errors = {};
    
    // 名前のバリデーション
    const name = this.form.querySelector('[name="name"]').value;
    if (!name.trim()) {
      this.errors.name = '名前は必須です';
    } else if (name.length < 2) {
      this.errors.name = '名前は2文字以上で入力してください';
    }
    
    // メールのバリデーション
    const email = this.form.querySelector('[name="email"]').value;
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!email.trim()) {
      this.errors.email = 'メールアドレスは必須です';
    } else if (!emailRegex.test(email)) {
      this.errors.email = '正しいメールアドレスを入力してください';
    }
    
    return Object.keys(this.errors).length === 0;
  }
  
  displayErrors() {
    // エラーメッセージの表示
    Object.keys(this.errors).forEach(field => {
      const errorElement = document.querySelector(`#${field}-error`);
      if (errorElement) {
        errorElement.textContent = this.errors[field];
        errorElement.style.display = 'block';
      }
    });
  }
  
  onSuccess() {
    console.log('フォーム送信成功！');
    this.form.reset();
  }
}

// 使用例
const form = document.getElementById('contactForm');
new FormValidator(form);
```

### 2. APIデータの取得と表示

```javascript
class UserManager {
  constructor(containerElement) {
    this.container = containerElement;
    this.users = [];
    this.loading = false;
  }
  
  async fetchUsers() {
    if (this.loading) return;
    
    this.loading = true;
    this.showLoading();
    
    try {
      // 実際のAPIエンドポイントに置き換え
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      
      this.users = await response.json();
      this.render();
    } catch (error) {
      this.showError(error.message);
    } finally {
      this.loading = false;
      this.hideLoading();
    }
  }
  
  render() {
    this.container.innerHTML = '';
    
    this.users.forEach(user => {
      const userCard = this.createUserCard(user);
      this.container.appendChild(userCard);
    });
  }
  
  createUserCard(user) {
    const card = document.createElement('div');
    card.className = 'user-card';
    card.innerHTML = `
      <h3>${user.name}</h3>
      <p>Email: ${user.email}</p>
      <p>Phone: ${user.phone}</p>
      <p>Website: ${user.website}</p>
    `;
    return card;
  }
  
  showLoading() {
    this.container.innerHTML = '<div class="loading">読み込み中...</div>';
  }
  
  hideLoading() {
    const loading = this.container.querySelector('.loading');
    if (loading) {
      loading.remove();
    }
  }
  
  showError(message) {
    this.container.innerHTML = `<div class="error">エラー: ${message}</div>`;
  }
}

// 使用例
const userContainer = document.getElementById('userContainer');
const userManager = new UserManager(userContainer);

// ボタンクリックでユーザー情報を取得
document.getElementById('loadUsers').addEventListener('click', () => {
  userManager.fetchUsers();
});
```

### 3. ローカルストレージを使った設定管理

```javascript
class SettingsManager {
  constructor() {
    this.settings = this.loadSettings();
  }
  
  loadSettings() {
    try {
      const saved = localStorage.getItem('appSettings');
      return saved ? JSON.parse(saved) : this.getDefaultSettings();
    } catch (error) {
      console.error('設定の読み込みに失敗:', error);
      return this.getDefaultSettings();
    }
  }
  
  getDefaultSettings() {
    return {
      theme: 'light',
      language: 'ja',
      notifications: true,
      autoSave: true
    };
  }
  
  saveSetting(key, value) {
    this.settings[key] = value;
    this.saveToLocalStorage();
    this.applySettings();
  }
  
  saveToLocalStorage() {
    try {
      localStorage.setItem('appSettings', JSON.stringify(this.settings));
    } catch (error) {
      console.error('設定の保存に失敗:', error);
    }
  }
  
  applySettings() {
    // テーマの適用
    document.body.className = `theme-${this.settings.theme}`;
    
    // 言語設定の適用
    document.documentElement.lang = this.settings.language;
    
    // その他の設定反映
    if (this.settings.notifications) {
      this.enableNotifications();
    }
  }
  
  enableNotifications() {
    if ('Notification' in window) {
      Notification.requestPermission();
    }
  }
  
  getSetting(key) {
    return this.settings[key];
  }
  
  getAllSettings() {
    return { ...this.settings };
  }
}

// 使用例
const settings = new SettingsManager();

// 設定画面での使用
document.getElementById('themeSelect').addEventListener('change', (e) => {
  settings.saveSetting('theme', e.target.value);
});

document.getElementById('languageSelect').addEventListener('change', (e) => {
  settings.saveSetting('language', e.target.value);
});
```

---

## 16. 学習の進め方とリソース

### 段階的学習プラン

#### レベル1: 基礎固め（1-2週間）
- [ ] JavaScript の基本概念理解
- [ ] データ型と変数の使い方
- [ ] 関数の定義と呼び出し
- [ ] 基本的な制御構文
- [ ] Math オブジェクトの活用

#### レベル2: 実践入門（2-3週間）
- [ ] 配列とオブジェクトの操作
- [ ] DOM 操作の基本
- [ ] イベント処理の実装
- [ ] 簡単な Web アプリケーション作成

#### レベル3: 応用技術（3-4週間）
- [ ] 非同期処理（Promise, async/await）
- [ ] エラーハンドリング
- [ ] API との連携
- [ ] モダン JavaScript（ES6+）

#### レベル4: 実践開発（継続的）
- [ ] フレームワークの学習（React, Vue.js など）
- [ ] バックエンド技術（Node.js）
- [ ] 開発ツールの活用
- [ ] 実際のプロジェクト開発

### 推奨学習リソース

#### 公式ドキュメント
- **MDN Web Docs**: JavaScript の最も信頼できるリファレンス
- **ECMAScript仕様**: 言語仕様の詳細

#### 実践的な学習サイト
- **freeCodeCamp**: 無料のプログラミング学習
- **Codecademy**: インタラクティブな学習環境
- **JavaScript.info**: 詳細な解説と実例

#### 開発環境
- **Visual Studio Code**: 無料で高機能なエディタ
- **Chrome DevTools**: デバッグとパフォーマンス分析
- **Node.js**: サーバーサイド JavaScript 実行環境

---

## まとめ

このガイドでは、JavaScript の基礎から実践的な応用まで、体系的に学習できる内容をまとめました。

### 重要なポイント
1. **Math オブジェクト**は数学的処理の基本ツール
2. **グローバルオブジェクト**と**ビルトインオブジェクト**の理解が重要
3. **DOM 操作**と**イベント処理**で動的な Web アプリが作れる
4. **非同期処理**は現代の Web 開発に必須
5. **エラーハンドリング**で堅牢なアプリケーションを構築

### 学習のコツ
- **小さなプロジェクトから始める**
- **実際にコードを書いて動かす**
- **エラーを恐れずデバッグスキルを身につける**
- **継続的に新しい技術をキャッチアップする**

JavaScript は Web 開発の基盤技術として、今後も重要性が増していきます。この ガイドを参考に、着実にスキルアップを図っていきましょう。

---

## 付録: チートシート

### Math オブジェクト早見表
```javascript
Math.random()          // 乱数生成
Math.floor(4.7)        // 4 (切り捨て)
Math.ceil(4.1)         // 5 (切り上げ)
Math.round(4.5)        // 5 (四捨五入)
Math.max(1, 5, 3)      // 5 (最大値)
Math.min(1, 5, 3)      // 1 (最小値)
Math.abs(-5)           // 5 (絶対値)
Math.pow(2, 3)         // 8 (2の3乗)
Math.sqrt(25)          // 5 (平方根)
Math.PI                // 3.14159... (円周率)
```

### DOM 操作早見表
```javascript
// 要素の取得
document.getElementById('id')
document.querySelector('.class')
document.querySelectorAll('tag')

// 内容の変更
element.textContent = 'text'
element.innerHTML = '<p>html</p>'

// スタイルの変更
element.style.color = 'red'
element.classList.add('class')

// イベントの追加
element.addEventListener('click', function)
```

### 配列メソッド早見表
```javascript
// 変更を伴う
arr.push(item)         // 末尾に追加
arr.pop()              // 末尾を削除
arr.unshift(item)      // 先頭に追加
arr.shift()            // 先頭を削除

// 新しい配列を返す
arr.map(fn)            // 各要素を変換
arr.filter(fn)         // 条件に合う要素を抽出
arr.reduce(fn, init)   // 1つの値に集約
arr.concat(arr2)       // 配列を結合
arr.slice(start, end)  // 一部を抽出
```

この完全版ガイドが、JavaScript 学習の道標となれば幸いです。