Lecture 1JavaScriptとは — Webを動かす唯一の言語
8:00
JavaScriptとは — Webを動かす唯一の言語
Web の3つの言語の役割分担
前提コース「HTML/CSS入門」では、Web の構造(HTML)と見た目(CSS)を学びました。しかし、「ボタンをクリックしたらメニューが開く」「入力内容をリアルタイムにチェックする」「サーバーからデータを取得して表示する」— これらの動きは HTML と CSS だけでは実現できません。
| 言語 | 役割 | 例 |
|---|---|---|
| HTML | 構造 | 見出し、段落、画像、フォーム |
| CSS | 見た目 | 色、配置、アニメーション |
| JavaScript | 動き | クリック反応、データ取得、計算 |
JavaScript は ブラウザで動作する唯一のプログラミング言語 です。
JavaScript の歴史
| 年 | 出来事 |
|---|---|
| 1995 | Brendan Eich が Netscape 社で10日間で開発(当初の名前は Mocha) |
| 1997 | ECMAScript として標準化(ECMA-262) |
| 2009 | Node.js 登場(サーバーサイドでも JavaScript が使えるように) |
| 2015 | ES6(ES2015) — 現代 JavaScript の基礎(let/const, アロー関数, クラス, Promise) |
| 毎年 | ECMAScript は年次リリースで進化中(ES2024 が最新) |
ES6 以降が「モダン JavaScript」 です。本講座では ES6+ の書き方を使います。
JavaScript でできること
ブラウザ側(フロントエンド)
- DOM操作: HTML の要素を追加・変更・削除
- イベント処理: クリック、キー入力、スクロールに反応
- API通信: サーバーからデータを取得して表示
- アニメーション: 要素を動かす、フェードイン/アウト
- フォームバリデーション: 入力内容のリアルタイムチェック
サーバー側(バックエンド — Node.js)
- Web サーバーの構築(Express, Fastify)
- データベース操作
- ファイル処理
- API の作成
本講座では フロントエンド(ブラウザ側) に集中します。
開発環境
HTML/CSS入門で使った VS Code + Chrome がそのまま使えます。追加のインストールは不要です。
Console を使ってみる
- Chrome を開く
- F12 → Console タブ
- 以下を入力して Enter:
console.log("Hello, JavaScript!");
画面に Hello, JavaScript! と表示されれば成功です。
Console でできること
// 計算
2 + 3 // → 5
10 * 20 // → 200
"Hello" + " " + "World" // → "Hello World"
// 日付
new Date() // → 現在の日時
// アラート(ポップアップ)
alert("こんにちは!")
Console はプログラミングの実験場です。迷ったらまず Console で試してみてください。
HTML ファイルに JavaScript を書く
script タグ(インライン)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>JavaScript入門</title>
</head>
<body>
<h1 id="title">こんにちは</h1>
<button id="btn">クリック</button>
<script>
document.getElementById("btn").addEventListener("click", function() {
document.getElementById("title").textContent = "ボタンが押されました!";
});
</script>
</body>
</html>
外部ファイル(推奨)
<!-- index.html -->
<body>
<h1 id="title">こんにちは</h1>
<button id="btn">クリック</button>
<script src="js/main.js"></script>
</body>
// js/main.js
document.getElementById("btn").addEventListener("click", function() {
document.getElementById("title").textContent = "ボタンが押されました!";
});
script タグの配置
</body> の直前に配置する のが基本です。理由:
- HTML の解析が完了してから JavaScript が実行される
- DOM要素が確実に存在する状態でアクセスできる
- ページ表示がブロックされない
または defer 属性を使う方法もあります:
<head>
<script src="js/main.js" defer></script>
</head>
defer は HTML の解析完了後に実行する指定です。現代の開発ではこちらも一般的です。
コメント
// 1行コメント
/*
複数行
コメント
*/
// コメントはコードの意図を説明する(「何をしているか」ではなく「なぜそうしているか」)
セミコロン
JavaScript ではセミコロン(;)は省略可能ですが、付ける習慣を推奨 します。ASI(Automatic Semicolon Insertion)に頼ると、まれに意図しない動作になることがあります。
// 推奨
const name = "田中";
console.log(name);
// 省略しても動く(が非推奨)
const name = "田中"
console.log(name)
実践ワーク
my-js-appフォルダを作成、index.htmlとjs/main.jsを作成- Chrome Console で
console.log(),alert(), 計算を試す - ボタンをクリックするとテキストが変わる仕組みを実装
console.log("デバッグメッセージ")で Console にメッセージを出す
まとめと次回の準備
今回のポイント:
- JavaScript は Web に動きを付ける唯一のブラウザ言語
- ES6(2015年)以降が「モダン JavaScript」
- Chrome Console で手軽にコードを試せる
- <script> は </body> 直前に配置(または defer)
次回: 変数、データ型、演算子を学びます。プログラミングの基礎中の基礎で、すべてのコードの出発点です。
参考文献: - MDN Web Docs「JavaScript 第一歩」(https://developer.mozilla.org/ja/docs/Learn/JavaScript/First_steps) - ECMA International「ECMAScript 仕様」(https://tc39.es/ecma262/) - Douglas Crockford『JavaScript: The Good Parts』(O'Reilly, 2008)
Lecture 2変数・データ型・演算子 — データを扱う基本
12:00
変数・データ型・演算子 — データを扱う基本
変数とは
変数は データに名前を付けて保存する箱 です。
let(再代入可能)
let score = 0;
console.log(score); // 0
score = 100; // 再代入OK
console.log(score); // 100
const(再代入不可 — 推奨)
const TAX_RATE = 0.1;
console.log(TAX_RATE); // 0.1
TAX_RATE = 0.08; // エラー: Assignment to constant variable.
var(古い書き方 — 使わない)
var name = "田中"; // ES6以前の書き方。使わないでください
var はスコープの挙動が直感に反するため、現代の JavaScript では使いません。
使い分けルール
const をデフォルトで使い、再代入が必要な場合のみ let を使う。 var は使わない。
const userName = "田中太郎"; // 変更しない値 → const
const MAX_RETRIES = 3; // 定数 → const
let count = 0; // ループカウンタなど → let
let isLoggedIn = false; // 状態が変わる → let
命名規則
// camelCase(推奨)
const userName = "田中";
const totalPrice = 1000;
const isActive = true;
// NG: 予約語
// const let = 5; // エラー
// const class = "A"; // エラー
// NG: 数字始まり
// const 1stPlace = "田中"; // エラー
データ型
JavaScript には 7つのプリミティブ型 と オブジェクト型 があります。
プリミティブ型
// 1. 文字列(string)
const name = "田中太郎";
const greeting = 'こんにちは';
const message = `${name}さん、${greeting}`; // テンプレートリテラル
// 2. 数値(number)
const age = 30;
const price = 1980.5;
const negative = -10;
// 3. 真偽値(boolean)
const isActive = true;
const isDeleted = false;
// 4. undefined(未定義)
let data;
console.log(data); // undefined
// 5. null(意図的に「空」)
const result = null;
// 6. BigInt(巨大整数 — ES2020)
const bigNumber = 9007199254740992n;
// 7. Symbol(一意の識別子 — ES6)
const id = Symbol("id");
typeof 演算子
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" ← 配列もobject
テンプレートリテラル(バッククォート)
const name = "田中";
const age = 30;
// 従来の文字列結合
const msg1 = name + "さんは" + age + "歳です。";
// テンプレートリテラル(推奨)
const msg2 = `${name}さんは${age}歳です。`;
// 複数行もOK
const html = `
<div class="card">
<h2>${name}</h2>
<p>${age}歳</p>
</div>
`;
型変換
JavaScript は動的型付け言語で、型が自動変換されることがあります。
暗黙の型変換(危険)
console.log("5" + 3); // "53"(文字列結合)
console.log("5" - 3); // 2(数値として計算)
console.log("5" * "3"); // 15
console.log(true + 1); // 2(true → 1)
console.log(false + 1); // 1(false → 0)
明示的な型変換(安全)
// 文字列 → 数値
const num1 = Number("42"); // 42
const num2 = parseInt("42px"); // 42(先頭の数値部分だけ)
const num3 = parseFloat("3.14"); // 3.14
// 数値 → 文字列
const str1 = String(42); // "42"
const str2 = (42).toString(); // "42"
// 真偽値
const bool1 = Boolean(0); // false
const bool2 = Boolean(""); // false
const bool3 = Boolean("hello"); // true
const bool4 = Boolean(1); // true
Falsy 値(false と判定される値)
// 以下はすべて false になる
Boolean(false) // false
Boolean(0) // false
Boolean("") // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(NaN) // false
// それ以外はすべて true(Truthy)
Boolean("0") // true(文字列の"0"はTruthy)
Boolean([]) // true(空配列はTruthy)
Boolean({}) // true(空オブジェクトはTruthy)
演算子
算術演算子
console.log(10 + 3); // 13(加算)
console.log(10 - 3); // 7(減算)
console.log(10 * 3); // 30(乗算)
console.log(10 / 3); // 3.333...(除算)
console.log(10 % 3); // 1(剰余)
console.log(2 ** 10); // 1024(べき乗 — ES2016)
比較演算子
// === 厳密等価(推奨)— 型も値も同じ
console.log(5 === 5); // true
console.log(5 === "5"); // false
// == 等価(非推奨)— 型変換して比較
console.log(5 == "5"); // true(危険!)
console.log(0 == false); // true(危険!)
// !== 厳密不等価(推奨)
console.log(5 !== "5"); // true
// 大小比較
console.log(10 > 5); // true
console.log(10 >= 10); // true
console.log(10 < 5); // false
console.log(10 <= 10); // true
常に === と !== を使ってください。 == と != は暗黙の型変換が入り、バグの温床です。
論理演算子
// AND(両方 true のとき true)
console.log(true && true); // true
console.log(true && false); // false
// OR(どちらか true のとき true)
console.log(true || false); // true
console.log(false || false); // false
// NOT(反転)
console.log(!true); // false
console.log(!false); // true
// 実用例
const age = 25;
const hasLicense = true;
if (age >= 18 && hasLicense) {
console.log("運転できます");
}
Null合体演算子(?? — ES2020)
const input = null;
const value = input ?? "デフォルト値";
console.log(value); // "デフォルト値"
// || との違い
const count = 0;
console.log(count || 10); // 10(0 は falsy なので)
console.log(count ?? 10); // 0(null/undefined のみ置換)
代入演算子
let x = 10;
x += 5; // x = x + 5 → 15
x -= 3; // x = x - 3 → 12
x *= 2; // x = x * 2 → 24
x /= 4; // x = x / 4 → 6
x++; // x = x + 1 → 7
x--; // x = x - 1 → 6
実践ワーク
Console で以下を試してください:
// 1. 変数と計算
const price = 1980;
const quantity = 3;
const taxRate = 0.1;
const total = price * quantity * (1 + taxRate);
console.log(`合計: ${total}円`);
// 2. 型変換の確認
console.log(typeof "42");
console.log(typeof Number("42"));
console.log("5" + 3);
console.log("5" - 3);
// 3. 比較演算子
console.log(5 === "5");
console.log(5 == "5");
// 4. BMI計算
const height = 1.70; // メートル
const weight = 65; // kg
const bmi = weight / (height ** 2);
console.log(`BMI: ${bmi.toFixed(1)}`);
まとめと次回の準備
今回のポイント:
- const がデフォルト、再代入が必要なら let。var は使わない
- テンプレートリテラル `${変数}` で文字列を組み立てる
- === で厳密比較。== は使わない
- Falsy 値(0, "", null, undefined, NaN, false)を理解する
次回: 条件分岐(if / switch)とループ(for / while)。プログラムの流れを制御する基本構造を学びます。
参考文献: - MDN Web Docs「JavaScript データ型とデータ構造」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Data_structures) - MDN Web Docs「式と演算子」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Expressions_and_operators)
Lecture 3条件分岐とループ — プログラムの流れを制御する
12:00
条件分岐とループ — プログラムの流れを制御する
条件分岐
if 文
const score = 85;
if (score >= 90) {
console.log("優");
} else if (score >= 70) {
console.log("良");
} else if (score >= 60) {
console.log("可");
} else {
console.log("不可");
}
// → "良"
三項演算子(1行で書ける if)
const age = 20;
const message = age >= 18 ? "成人です" : "未成年です";
console.log(message); // "成人です"
// 実用例: CSSクラスの切り替え
const isActive = true;
const className = isActive ? "btn-active" : "btn-inactive";
三項演算子はシンプルな2択に使います。複雑な条件には if 文を使ってください。
switch 文
const day = new Date().getDay(); // 0(日)〜 6(土)
switch (day) {
case 0:
console.log("日曜日");
break;
case 1:
console.log("月曜日");
break;
case 2:
console.log("火曜日");
break;
case 6:
console.log("土曜日");
break;
default:
console.log("平日です");
}
break を忘れるとフォールスルー(次の case も実行される)になるので注意してください。
論理演算子を使った条件
const user = { name: "田中", age: 30, isPremium: true };
// AND: 両方の条件を満たす
if (user.age >= 18 && user.isPremium) {
console.log("プレミアムコンテンツにアクセス可能");
}
// OR: どちらかの条件を満たす
if (user.isPremium || user.age >= 65) {
console.log("割引適用");
}
// NOT: 条件の否定
if (!user.isPremium) {
console.log("アップグレードをおすすめします");
}
オプショナルチェイニング(?. — ES2020)
const user = { name: "田中", address: null };
// 従来: エラー回避のために if が必要
if (user.address && user.address.city) {
console.log(user.address.city);
}
// オプショナルチェイニング: 安全にアクセス
console.log(user.address?.city); // undefined(エラーにならない)
ループ(繰り返し)
for 文
for (let i = 0; i < 5; i++) {
console.log(`${i + 1}回目`);
}
// 1回目, 2回目, 3回目, 4回目, 5回目
構造: for (初期化; 条件; 更新)
while 文
let count = 0;
while (count < 5) {
console.log(`${count + 1}回目`);
count++;
}
注意: 条件が永遠に true になるとブラウザがフリーズします(無限ループ)。必ず終了条件を設定してください。
for...of(配列の反復 — 推奨)
const fruits = ["りんご", "バナナ", "オレンジ"];
for (const fruit of fruits) {
console.log(fruit);
}
// りんご, バナナ, オレンジ
for...in(オブジェクトのキー反復)
const user = { name: "田中", age: 30, city: "東京" };
for (const key in user) {
console.log(`${key}: ${user[key]}`);
}
// name: 田中, age: 30, city: 東京
配列のメソッドによるループ(最も使用頻度が高い)
const numbers = [1, 2, 3, 4, 5];
// forEach: 各要素に処理を実行
numbers.forEach(function(num) {
console.log(num * 2);
});
// 2, 4, 6, 8, 10
// forEach(アロー関数版)
numbers.forEach((num) => {
console.log(num * 2);
});
アロー関数は次回「関数」の講義で詳しく学びます。
break と continue
// break: ループを途中で抜ける
for (let i = 0; i < 10; i++) {
if (i === 5) break;
console.log(i);
}
// 0, 1, 2, 3, 4
// continue: 現在の回をスキップして次へ
for (let i = 0; i < 10; i++) {
if (i % 2 === 0) continue; // 偶数をスキップ
console.log(i);
}
// 1, 3, 5, 7, 9
実践的な例
FizzBuzz
プログラミングの定番問題です。
for (let i = 1; i <= 30; i++) {
if (i % 15 === 0) {
console.log("FizzBuzz");
} else if (i % 3 === 0) {
console.log("Fizz");
} else if (i % 5 === 0) {
console.log("Buzz");
} else {
console.log(i);
}
}
合計・平均の計算
const scores = [80, 95, 70, 88, 92];
let total = 0;
for (const score of scores) {
total += score;
}
const average = total / scores.length;
console.log(`合計: ${total}`); // 425
console.log(`平均: ${average}`); // 85
入力バリデーション
const email = "user@example.com";
if (email.length === 0) {
console.log("メールアドレスを入力してください");
} else if (!email.includes("@")) {
console.log("正しいメールアドレスを入力してください");
} else {
console.log("OK");
}
九九の表
for (let i = 1; i <= 9; i++) {
let row = "";
for (let j = 1; j <= 9; j++) {
row += String(i * j).padStart(4);
}
console.log(row);
}
実践ワーク
Console で以下を作成してください:
- 成績判定: 点数(0-100)を入力し、90以上=A、80以上=B、70以上=C、60以上=D、それ以下=F を表示
- FizzBuzz: 1〜50 まで実行
- 最大値の検索: 配列
[34, 72, 13, 55, 89, 21]の中から最大値を for 文で見つける - 文字列の逆転:
"JavaScript"を1文字ずつループで逆順にする
まとめと次回の準備
今回のポイント:
- if / else if / else で条件分岐。三項演算子は単純な2択に
- for ループと while ループ。無限ループに注意
- for...of は配列、for...in はオブジェクトに使う
- ?.(オプショナルチェイニング)で安全にプロパティアクセス
次回: 関数を学びます。コードを部品化して再利用するための最も重要な概念です。
参考文献: - MDN Web Docs「制御フローとエラー処理」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Control_flow_and_error_handling) - MDN Web Docs「ループと反復処理」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Loops_and_iteration)
Lecture 4関数 — コードを部品化して再利用する
12:00
関数 — コードを部品化して再利用する
関数とは
関数は 入力を受け取り、処理して、結果を返す部品 です。同じ処理を何度も書かずに済みます。
関数の3つの書き方
1. function 宣言
function greet(name) {
return `こんにちは、${name}さん!`;
}
console.log(greet("田中")); // "こんにちは、田中さん!"
2. 関数式
const greet = function(name) {
return `こんにちは、${name}さん!`;
};
console.log(greet("田中"));
3. アロー関数(ES6 — 推奨)
const greet = (name) => {
return `こんにちは、${name}さん!`;
};
// 1行の場合は {} と return を省略できる
const greet = (name) => `こんにちは、${name}さん!`;
// 引数が1つの場合は () も省略できる
const greet = name => `こんにちは、${name}さん!`;
console.log(greet("田中"));
アロー関数を基本的に使ってください。 短く書けて、this の挙動も直感的です。
引数と戻り値
複数の引数
const add = (a, b) => a + b;
console.log(add(3, 5)); // 8
const introduce = (name, age, city) => {
return `${name}(${age}歳、${city}在住)`;
};
console.log(introduce("田中", 30, "東京"));
デフォルト引数(ES6)
const greet = (name, greeting = "こんにちは") => {
return `${greeting}、${name}さん!`;
};
console.log(greet("田中")); // "こんにちは、田中さん!"
console.log(greet("田中", "おはよう")); // "おはよう、田中さん!"
戻り値がない関数
const logMessage = (message) => {
console.log(`[LOG] ${message}`);
// return がなければ undefined を返す
};
const result = logMessage("テスト");
console.log(result); // undefined
早期リターン
const divide = (a, b) => {
if (b === 0) {
return "エラー: 0で割れません"; // 早期リターン
}
return a / b;
};
console.log(divide(10, 3)); // 3.333...
console.log(divide(10, 0)); // "エラー: 0で割れません"
スコープ
変数が見える範囲(スコープ)を理解することは重要です。
ブロックスコープ(let / const)
const x = "グローバル";
if (true) {
const y = "ブロック内";
console.log(x); // "グローバル"(外側は見える)
console.log(y); // "ブロック内"
}
console.log(x); // "グローバル"
// console.log(y); // エラー: y is not defined
関数スコープ
const outer = () => {
const message = "外側の関数";
const inner = () => {
console.log(message); // "外側の関数"(外側は見える)
};
inner();
};
outer();
// console.log(message); // エラー: message is not defined
コールバック関数
関数を別の関数の引数として渡す — これが コールバック です。JavaScript の最重要概念の一つです。
// 高階関数: 関数を引数に取る関数
const doTask = (task, callback) => {
console.log(`${task}を実行中...`);
callback();
};
doTask("データ取得", () => {
console.log("完了しました!");
});
// "データ取得を実行中..."
// "完了しました!"
配列メソッドとコールバック
const numbers = [1, 2, 3, 4, 5];
// map: 各要素を変換して新しい配列を返す
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter: 条件に合う要素だけの配列を返す
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]
// find: 条件に合う最初の要素を返す
const found = numbers.find(n => n > 3);
console.log(found); // 4
// reduce: 全要素を1つの値にまとめる
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 15
これらのメソッドは for ループより 宣言的 で読みやすいコードが書けます。
メソッドチェイン
const users = [
{ name: "田中", age: 30, active: true },
{ name: "鈴木", age: 25, active: false },
{ name: "佐藤", age: 35, active: true },
{ name: "山田", age: 28, active: true },
];
// アクティブなユーザーの名前を年齢順で取得
const result = users
.filter(user => user.active)
.sort((a, b) => a.age - b.age)
.map(user => user.name);
console.log(result); // ["山田", "田中", "佐藤"]
分割代入(Destructuring — ES6)
オブジェクトの分割代入
const user = { name: "田中", age: 30, city: "東京" };
// 従来
const name = user.name;
const age = user.age;
// 分割代入
const { name, age, city } = user;
console.log(name); // "田中"
console.log(age); // 30
// 関数の引数で使う(頻出パターン)
const greetUser = ({ name, age }) => {
return `${name}さん(${age}歳)`;
};
console.log(greetUser(user));
配列の分割代入
const colors = ["赤", "青", "緑"];
const [first, second, third] = colors;
console.log(first); // "赤"
console.log(second); // "青"
// 不要な要素をスキップ
const [, , last] = colors;
console.log(last); // "緑"
スプレッド構文(... — ES6)
// 配列のコピー・結合
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// オブジェクトのコピー・マージ
const defaults = { theme: "light", lang: "ja", fontSize: 16 };
const userSettings = { theme: "dark", fontSize: 18 };
const settings = { ...defaults, ...userSettings };
console.log(settings); // { theme: "dark", lang: "ja", fontSize: 18 }
// 残余引数
const sum = (...nums) => nums.reduce((acc, n) => acc + n, 0);
console.log(sum(1, 2, 3, 4, 5)); // 15
実践ワーク
// 1. 税込価格計算関数
const calcTax = (price, taxRate = 0.1) => {
return Math.floor(price * (1 + taxRate));
};
console.log(calcTax(1000)); // 1100
console.log(calcTax(1000, 0.08)); // 1080
// 2. 配列の統計関数
const stats = (numbers) => {
const sum = numbers.reduce((acc, n) => acc + n, 0);
const avg = sum / numbers.length;
const max = Math.max(...numbers);
const min = Math.min(...numbers);
return { sum, avg, max, min };
};
console.log(stats([80, 95, 70, 88, 92]));
// 3. ユーザーフィルタリング
const users = [
{ name: "田中", age: 30, city: "東京" },
{ name: "鈴木", age: 25, city: "大阪" },
{ name: "佐藤", age: 35, city: "東京" },
];
const tokyoUsers = users
.filter(u => u.city === "東京")
.map(u => u.name);
console.log(tokyoUsers); // ["田中", "佐藤"]
まとめと次回の準備
今回のポイント:
- アロー関数 () => {} を基本的に使う
- デフォルト引数で柔軟な関数設計
- map, filter, find, reduce は for ループより宣言的
- 分割代入とスプレッド構文で簡潔にデータを扱う
次回: 配列とオブジェクトを深く学びます。JavaScript のデータ構造の中核です。
参考文献: - MDN Web Docs「関数」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Functions) - MDN Web Docs「アロー関数式」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - MDN Web Docs「分割代入」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)
Lecture 5配列とオブジェクト — データをまとめて管理する
12:00
配列とオブジェクト — データをまとめて管理する
配列(Array)
配列は 順序を持つデータの集まり です。
配列の作成
const fruits = ["りんご", "バナナ", "オレンジ"];
const numbers = [1, 2, 3, 4, 5];
const mixed = ["文字列", 42, true, null]; // 異なる型の混在も可能(非推奨)
const empty = [];
要素へのアクセス
const fruits = ["りんご", "バナナ", "オレンジ"];
console.log(fruits[0]); // "りんご"(インデックスは0から)
console.log(fruits[1]); // "バナナ"
console.log(fruits[2]); // "オレンジ"
console.log(fruits.length); // 3
// 末尾の要素
console.log(fruits[fruits.length - 1]); // "オレンジ"
console.log(fruits.at(-1)); // "オレンジ"(ES2022)
配列の操作メソッド
要素の追加・削除
const arr = ["a", "b", "c"];
arr.push("d"); // 末尾に追加 → ["a", "b", "c", "d"]
arr.pop(); // 末尾を削除 → ["a", "b", "c"]
arr.unshift("z"); // 先頭に追加 → ["z", "a", "b", "c"]
arr.shift(); // 先頭を削除 → ["a", "b", "c"]
// splice: 任意の位置で追加/削除
arr.splice(1, 1); // index 1 から1個削除 → ["a", "c"]
arr.splice(1, 0, "x", "y"); // index 1 に挿入 → ["a", "x", "y", "c"]
注意: push, pop, splice は元の配列を変更(破壊的操作)します。
非破壊的メソッド(新しい配列を返す)
const arr = [3, 1, 4, 1, 5, 9];
// スライス(部分配列)
const sliced = arr.slice(1, 4); // [1, 4, 1](元の配列は変わらない)
// 結合
const joined = arr.concat([2, 6]); // [3, 1, 4, 1, 5, 9, 2, 6]
// ソート(非破壊版 — ES2023)
const sorted = arr.toSorted((a, b) => a - b); // [1, 1, 3, 4, 5, 9]
// 反転(非破壊版 — ES2023)
const reversed = arr.toReversed(); // [9, 5, 1, 4, 1, 3]
// 含まれるか
console.log(arr.includes(4)); // true
console.log(arr.indexOf(4)); // 2(最初に見つかったインデックス)
変換メソッド(前回の復習 + 追加)
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// map: 変換
const squared = numbers.map(n => n ** 2);
// [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// filter: 抽出
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4, 6, 8, 10]
// reduce: 集約
const sum = numbers.reduce((acc, n) => acc + n, 0); // 55
// some: 1つでも条件を満たすか
const hasLargeNumber = numbers.some(n => n > 8); // true
// every: すべて条件を満たすか
const allPositive = numbers.every(n => n > 0); // true
// flat: ネストされた配列を平坦化
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.flat(); // [1, 2, 3, 4, 5, 6]
// flatMap: map + flat
const words = ["Hello World", "Good Morning"];
const chars = words.flatMap(s => s.split(" "));
// ["Hello", "World", "Good", "Morning"]
文字列との変換
// 配列 → 文字列
const arr = ["HTML", "CSS", "JavaScript"];
console.log(arr.join(", ")); // "HTML, CSS, JavaScript"
console.log(arr.join(" | ")); // "HTML | CSS | JavaScript"
// 文字列 → 配列
const csv = "田中,30,東京";
const parts = csv.split(","); // ["田中", "30", "東京"]
オブジェクト(Object)
オブジェクトは キーと値のペアの集まり です。
オブジェクトの作成
const user = {
name: "田中太郎",
age: 30,
email: "tanaka@example.com",
isActive: true,
hobbies: ["読書", "プログラミング"],
address: {
city: "東京",
zipCode: "100-0001"
}
};
プロパティへのアクセス
// ドット記法(推奨)
console.log(user.name); // "田中太郎"
console.log(user.address.city); // "東京"
// ブラケット記法(キーが変数の場合に使用)
const key = "name";
console.log(user[key]); // "田中太郎"
// キーにスペースやハイフンがある場合
const config = { "max-retries": 3 };
console.log(config["max-retries"]); // 3
プロパティの追加・変更・削除
const user = { name: "田中", age: 30 };
// 追加
user.email = "tanaka@example.com";
// 変更
user.age = 31;
// 削除
delete user.email;
console.log(user); // { name: "田中", age: 31 }
const で宣言しても、オブジェクトの プロパティ は変更できます。const が保護するのは変数の再代入(user = {} など)であって、中身の変更ではありません。
オブジェクトのメソッド
const keys = Object.keys(user); // ["name", "age"]
const values = Object.values(user); // ["田中", 31]
const entries = Object.entries(user); // [["name", "田中"], ["age", 31]]
// キーの存在チェック
console.log("name" in user); // true
console.log(user.hasOwnProperty("name")); // true
// オブジェクトのコピー(スプレッド構文)
const copy = { ...user };
// オブジェクトのマージ
const defaults = { theme: "light", lang: "ja" };
const settings = { theme: "dark" };
const merged = { ...defaults, ...settings };
// { theme: "dark", lang: "ja" }
Object.entries() + map(頻出パターン)
const prices = { apple: 150, banana: 100, orange: 200 };
const taxIncluded = Object.entries(prices).map(([name, price]) => {
return { name, price: Math.floor(price * 1.1) };
});
console.log(taxIncluded);
// [
// { name: "apple", price: 165 },
// { name: "banana", price: 110 },
// { name: "orange", price: 220 }
// ]
JSON
JSON(JavaScript Object Notation)は、JavaScript のオブジェクト構文に基づくデータ交換フォーマットです。API 通信でほぼ必ず使用します。
// オブジェクト → JSON文字列
const user = { name: "田中", age: 30 };
const json = JSON.stringify(user);
console.log(json); // '{"name":"田中","age":30}'
// JSON文字列 → オブジェクト
const parsed = JSON.parse(json);
console.log(parsed.name); // "田中"
// 整形出力(デバッグ用)
console.log(JSON.stringify(user, null, 2));
// {
// "name": "田中",
// "age": 30
// }
JSON と JavaScript オブジェクトの違い
| 項目 | JavaScript オブジェクト | JSON |
|---|---|---|
| キー | クォート省略可 | ダブルクォート必須 |
| 値 | 関数、undefined 可 | 文字列、数値、配列、オブジェクト、true/false/null のみ |
| コメント | 可 | 不可 |
| 末尾のカンマ | 可 | 不可 |
Map と Set
ES6 で追加されたデータ構造です。
Map(キーに任意の型を使える連想配列)
const map = new Map();
map.set("name", "田中");
map.set(42, "数値キー");
map.set(true, "真偽値キー");
console.log(map.get("name")); // "田中"
console.log(map.size); // 3
console.log(map.has("name")); // true
map.delete("name");
// 反復
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
Set(重複のない値の集合)
const set = new Set([1, 2, 3, 3, 3]);
console.log(set.size); // 3(重複は除去される)
set.add(4);
set.delete(1);
console.log(set.has(2)); // true
// 配列の重複除去(頻出テクニック)
const arr = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3]
実践ワーク
// 1. 商品一覧の処理
const products = [
{ name: "ノートPC", price: 89800, category: "電子機器" },
{ name: "マウス", price: 2980, category: "電子機器" },
{ name: "デスク", price: 15800, category: "家具" },
{ name: "チェア", price: 29800, category: "家具" },
{ name: "モニター", price: 34800, category: "電子機器" },
];
// カテゴリ別にグループ化
// 電子機器の合計金額を計算
// 価格が10000円以上の商品名をリストアップ
// 2. 配列の重複除去
const tags = ["JavaScript", "HTML", "CSS", "JavaScript", "HTML"];
// → ["JavaScript", "HTML", "CSS"]
まとめと次回の準備
今回のポイント:
- 配列: push/pop は破壊的、map/filter/slice は非破壊的
- オブジェクト: ドット記法でアクセス、Object.keys/values/entries で反復
- JSON: JSON.stringify() と JSON.parse() で変換
- Set で重複除去、Map で任意キーの連想配列
次回: DOM操作。JavaScript で HTML の要素を選択し、変更し、追加・削除する方法を学びます。Web アプリ開発の核心です。
参考文献: - MDN Web Docs「Array」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array) - MDN Web Docs「Object」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object) - MDN Web Docs「JSON」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON)
Lecture 6DOM操作の基本 — HTMLをJavaScriptで動かす
12:00
DOM操作の基本 — HTMLをJavaScriptで動かす
DOMとは
DOM(Document Object Model)は、HTML をツリー構造のオブジェクトとして表現したものです。JavaScript はこの DOM を通じて HTML を読み取り、変更します。
<html>
<body>
<h1>タイトル</h1>
<p>段落</p>
</body>
</html>
document
└── html
└── body
├── h1 → "タイトル"
└── p → "段落"
すべての HTML タグは ノード(node) として DOM ツリーに存在し、JavaScript でアクセスできます。
要素の取得
querySelector(推奨 — CSS セレクタで取得)
// IDで取得
const title = document.querySelector("#title");
// クラスで取得(最初に見つかった1つ)
const card = document.querySelector(".card");
// タグで取得
const firstParagraph = document.querySelector("p");
// 複合セレクタ
const navLink = document.querySelector("nav a.active");
const firstItem = document.querySelector("ul > li:first-child");
querySelectorAll(複数の要素を取得)
// すべての .card 要素
const cards = document.querySelectorAll(".card");
// NodeList(配列に似たオブジェクト)
console.log(cards.length); // 要素数
cards.forEach(card => {
console.log(card.textContent);
});
// 配列に変換(配列メソッドをすべて使いたい場合)
const cardsArray = [...cards];
従来のメソッド(参考)
const el1 = document.getElementById("title"); // ID(#なし)
const el2 = document.getElementsByClassName("card"); // クラス(.なし)
const el3 = document.getElementsByTagName("p"); // タグ
querySelector / querySelectorAll がより柔軟なため、こちらを使ってください。
テキストの変更
const title = document.querySelector("#title");
// textContent: テキストのみ(HTML無視、安全)
title.textContent = "新しいタイトル";
// innerHTML: HTMLを含む(XSS注意)
title.innerHTML = "新しい<em>タイトル</em>";
セキュリティ: ユーザー入力を innerHTML に直接入れると XSS(クロスサイトスクリプティング) の脆弱性になります。ユーザー入力は必ず textContent を使ってください。
// NG: XSS脆弱性
const userInput = '<img src=x onerror="alert(1)">';
element.innerHTML = userInput; // 危険!スクリプトが実行される
// OK: 安全
element.textContent = userInput; // テキストとして表示される
属性の操作
const link = document.querySelector("a");
// 取得
console.log(link.getAttribute("href"));
// 設定
link.setAttribute("href", "https://example.com");
link.setAttribute("target", "_blank");
// 削除
link.removeAttribute("target");
// 直接アクセス(一部の属性)
const img = document.querySelector("img");
img.src = "new-image.jpg";
img.alt = "新しい画像";
// data属性
const card = document.querySelector('[data-id="123"]');
console.log(card.dataset.id); // "123"
card.dataset.status = "active"; // data-status="active" を追加
CSSの操作
style プロパティ(インラインスタイル)
const box = document.querySelector(".box");
box.style.backgroundColor = "#007bff";
box.style.color = "white";
box.style.padding = "16px";
box.style.borderRadius = "8px";
// CSS: kebab-case → JS: camelCase
// background-color → backgroundColor
classList(クラスの操作 — 推奨)
const btn = document.querySelector(".btn");
btn.classList.add("active"); // クラスを追加
btn.classList.remove("active"); // クラスを削除
btn.classList.toggle("active"); // あれば削除、なければ追加
btn.classList.contains("active"); // 含まれるか(true/false)
btn.classList.replace("old", "new"); // クラスを置換
CSS は CSS ファイルに書き、JavaScript ではクラスの付け外しだけ行う のがベストプラクティスです。
/* style.css */
.hidden { display: none; }
.visible { display: block; }
.fade-in { opacity: 1; transition: opacity 0.3s; }
.fade-out { opacity: 0; transition: opacity 0.3s; }
// JS: クラスの切り替えだけ
element.classList.toggle("hidden");
要素の作成と追加
createElement + appendChild
// 新しい要素を作成
const newCard = document.createElement("div");
newCard.classList.add("card");
newCard.textContent = "新しいカード";
// 親要素に追加
const container = document.querySelector(".container");
container.appendChild(newCard);
insertAdjacentHTML(HTML文字列から追加)
const container = document.querySelector(".container");
container.insertAdjacentHTML("beforeend", `
<div class="card">
<h3>新しいカード</h3>
<p>テキスト</p>
</div>
`);
| 位置 | 説明 |
|---|---|
"beforebegin" |
要素の前 |
"afterbegin" |
要素の最初の子として |
"beforeend" |
要素の最後の子として |
"afterend" |
要素の後 |
要素の削除
const card = document.querySelector(".card");
card.remove(); // 要素を削除
フォームの値の取得
// テキスト入力
const nameInput = document.querySelector("#name");
console.log(nameInput.value); // 入力された文字列
// チェックボックス
const checkbox = document.querySelector("#agree");
console.log(checkbox.checked); // true / false
// セレクトボックス
const select = document.querySelector("#category");
console.log(select.value); // 選択された option の value
// テキストエリア
const textarea = document.querySelector("#message");
console.log(textarea.value); // 入力された文字列
実践: 動的なリスト
<input type="text" id="itemInput" placeholder="アイテムを入力">
<button id="addBtn">追加</button>
<ul id="list"></ul>
const input = document.querySelector("#itemInput");
const addBtn = document.querySelector("#addBtn");
const list = document.querySelector("#list");
addBtn.addEventListener("click", () => {
const text = input.value.trim();
if (text === "") return;
const li = document.createElement("li");
li.textContent = text;
// 削除ボタン
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "×";
deleteBtn.addEventListener("click", () => li.remove());
li.appendChild(deleteBtn);
list.appendChild(li);
input.value = ""; // 入力欄をクリア
input.focus(); // フォーカスを戻す
});
実践ワーク
- ボタンをクリックするとカウンターが増える/減る仕組みを作る
- テキスト入力欄にリアルタイムで文字数を表示する
- 「ダークモード切り替え」ボタンで
bodyにクラスをトグルする - 上の動的リストを実装し、削除ボタンも付ける
まとめと次回の準備
今回のポイント:
- querySelector / querySelectorAll で要素を取得
- textContent(安全)と innerHTML(XSS注意)でテキスト変更
- classList.toggle() で CSS クラスの付け外し
- createElement + appendChild で動的に要素を追加
- フォームの値は .value で取得
次回: イベント処理。クリック、入力、スクロール、キーボード — ユーザーの操作に反応するプログラムの書き方を学びます。
参考文献: - MDN Web Docs「DOM の紹介」(https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model/Introduction) - MDN Web Docs「Document.querySelector()」(https://developer.mozilla.org/ja/docs/Web/API/Document/querySelector) - OWASP「XSS Prevention」(https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
Lecture 7イベント処理 — クリック・入力・スクロールに反応する
12:00
イベント処理 — クリック・入力・スクロールに反応する
イベントとは
ユーザーがページ上で行う操作(クリック、キー入力、スクロールなど)を イベント と呼びます。JavaScript はイベントを検知して、それに応じた処理を実行できます。
addEventListener(イベントリスナーの登録)
const btn = document.querySelector("#myBtn");
btn.addEventListener("click", () => {
console.log("ボタンがクリックされました");
});
構文: 要素.addEventListener(イベント名, コールバック関数)
主要なイベント一覧
| カテゴリ | イベント名 | タイミング |
|---|---|---|
| マウス | click |
クリック時 |
dblclick |
ダブルクリック時 | |
mouseover |
マウスが乗った時 | |
mouseout |
マウスが離れた時 | |
| キーボード | keydown |
キーを押した時 |
keyup |
キーを離した時 | |
| フォーム | input |
入力内容が変わった時(リアルタイム) |
change |
値が確定した時(フォーカスが外れた時) | |
submit |
フォームが送信された時 | |
focus |
フォーカスを得た時 | |
blur |
フォーカスを失った時 | |
| ウィンドウ | scroll |
スクロール時 |
resize |
ウィンドウサイズ変更時 | |
DOMContentLoaded |
HTML解析完了時 | |
load |
すべてのリソース読み込み完了時 |
イベントオブジェクト
コールバック関数は イベントオブジェクト を引数として受け取ります。
const btn = document.querySelector("#myBtn");
btn.addEventListener("click", (event) => {
console.log(event.type); // "click"
console.log(event.target); // クリックされた要素
console.log(event.clientX); // マウスのX座標
console.log(event.clientY); // マウスのY座標
console.log(event.timeStamp); // イベント発生時刻
});
event.target(クリックされた要素)
document.querySelector(".card-list").addEventListener("click", (e) => {
console.log(e.target); // 実際にクリックされた要素
console.log(e.currentTarget); // イベントリスナーが付いた要素
});
キーボードイベント
document.addEventListener("keydown", (e) => {
console.log(e.key); // "Enter", "a", "ArrowUp" など
console.log(e.code); // "Enter", "KeyA", "ArrowUp" など
console.log(e.ctrlKey); // Ctrl が押されているか
console.log(e.shiftKey); // Shift が押されているか
// Ctrl+S でカスタム保存
if (e.ctrlKey && e.key === "s") {
e.preventDefault(); // ブラウザのデフォルト保存を抑止
console.log("カスタム保存を実行");
}
});
preventDefault(デフォルト動作の抑止)
// フォーム送信時にページ遷移を防ぐ
const form = document.querySelector("form");
form.addEventListener("submit", (e) => {
e.preventDefault(); // デフォルトの送信(ページ遷移)を抑止
const name = document.querySelector("#name").value;
const email = document.querySelector("#email").value;
console.log({ name, email });
// ここで fetch() を使ってAPI送信する(第8回で学習)
});
// リンクのデフォルト遷移を防ぐ
const link = document.querySelector("a");
link.addEventListener("click", (e) => {
e.preventDefault();
console.log("リンクのURLは:", e.target.href);
});
イベントの伝播(バブリング)
イベントは子要素から親要素に向かって バブリング(泡のように上がる)します。
<div id="parent">
<button id="child">クリック</button>
</div>
document.querySelector("#parent").addEventListener("click", () => {
console.log("親がクリックされた");
});
document.querySelector("#child").addEventListener("click", () => {
console.log("子がクリックされた");
});
// ボタンをクリックすると:
// "子がクリックされた"
// "親がクリックされた"(バブリングで親にも伝播)
stopPropagation(伝播の停止)
document.querySelector("#child").addEventListener("click", (e) => {
e.stopPropagation(); // 親への伝播を止める
console.log("子がクリックされた");
});
// ボタンをクリック → "子がクリックされた" のみ
イベント委任(Event Delegation)
多数の子要素にイベントリスナーを付ける代わりに、親要素に1つだけ付けるテクニックです。
<ul id="todoList">
<li>タスク1 <button class="delete">×</button></li>
<li>タスク2 <button class="delete">×</button></li>
<li>タスク3 <button class="delete">×</button></li>
<!-- 動的に追加されるアイテムにもイベントが効く -->
</ul>
// NG: 各ボタンにリスナーを付ける(動的追加に非対応)
document.querySelectorAll(".delete").forEach(btn => {
btn.addEventListener("click", () => { /* ... */ });
});
// OK: 親に1つだけリスナーを付ける(イベント委任)
document.querySelector("#todoList").addEventListener("click", (e) => {
if (e.target.classList.contains("delete")) {
e.target.closest("li").remove();
}
});
イベント委任の利点: 1. リスナーが1つだけなのでメモリ効率が良い 2. 動的に追加された要素にも自動的に効く 3. コードがシンプル
実践的なイベント処理パターン
リアルタイム文字数カウント
const textarea = document.querySelector("#message");
const counter = document.querySelector("#charCount");
const MAX_LENGTH = 200;
textarea.addEventListener("input", () => {
const remaining = MAX_LENGTH - textarea.value.length;
counter.textContent = `残り ${remaining} 文字`;
counter.style.color = remaining < 20 ? "red" : "#666";
});
アコーディオン(開閉パネル)
<div class="accordion">
<button class="accordion-header">セクション1</button>
<div class="accordion-body">
<p>コンテンツ1の内容</p>
</div>
<button class="accordion-header">セクション2</button>
<div class="accordion-body">
<p>コンテンツ2の内容</p>
</div>
</div>
.accordion-body {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.accordion-body.open {
max-height: 500px;
}
document.querySelector(".accordion").addEventListener("click", (e) => {
if (e.target.classList.contains("accordion-header")) {
const body = e.target.nextElementSibling;
body.classList.toggle("open");
}
});
スクロール時のヘッダー変化
let lastScrollY = 0;
window.addEventListener("scroll", () => {
const header = document.querySelector(".header");
const currentScrollY = window.scrollY;
if (currentScrollY > 100) {
header.classList.add("scrolled");
} else {
header.classList.remove("scrolled");
}
lastScrollY = currentScrollY;
});
debounce(連続イベントの抑制)
scroll や input イベントは1秒間に数十回発火します。負荷を抑えるために debounce を使います。
const debounce = (fn, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
};
// 入力が止まって300ms後に検索を実行
const searchInput = document.querySelector("#search");
searchInput.addEventListener("input", debounce((e) => {
console.log("検索:", e.target.value);
}, 300));
実践ワーク
- ボタンのクリックでカウンター(+1 / -1 / リセット)を実装
- テキストエリアにリアルタイム文字数カウンターを実装
- ダークモード切り替えボタン(
body.classList.toggle("dark")) - アコーディオン(イベント委任で実装)
まとめと次回の準備
今回のポイント:
- addEventListener でイベントを登録
- event.target でクリックされた要素を取得
- e.preventDefault() でデフォルト動作を抑止(フォーム送信など)
- イベント委任: 親に1つリスナーを付けて、動的要素にも対応
- debounce で連続イベントの負荷を抑制
次回: Module 2 に入り、非同期処理と API 通信を学びます。fetch() で外部データを取得し、ページに表示する方法です。
参考文献: - MDN Web Docs「イベント入門」(https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks/Events) - MDN Web Docs「EventTarget.addEventListener()」(https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener) - MDN Web Docs「イベントの伝播」(https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks/Event_bubbling)
Lecture 8非同期処理とAPI通信 — 外部データを取得する
12:00
非同期処理とAPI通信 — 外部データを取得する
同期処理と非同期処理
同期処理(今まで書いてきたコード)
console.log("1番目");
console.log("2番目");
console.log("3番目");
// 必ず 1 → 2 → 3 の順に実行
非同期処理
console.log("1番目");
setTimeout(() => {
console.log("2番目(1秒後)");
}, 1000);
console.log("3番目");
// 1番目 → 3番目 → 2番目(1秒後)
非同期処理は 待たずに次へ進む のが特徴です。API通信(サーバーとの通信)は数百ミリ秒〜数秒かかるため、非同期で行います。
Promise
Promise は非同期処理の結果を表すオブジェクトです。
const myPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve("成功しました"); // 成功時
} else {
reject("失敗しました"); // 失敗時
}
});
myPromise
.then(result => console.log(result)) // "成功しました"
.catch(error => console.log(error)); // エラー時
Promise の3つの状態
| 状態 | 意味 |
|---|---|
| pending | 処理中(まだ結果が出ていない) |
| fulfilled | 成功(resolve が呼ばれた) |
| rejected | 失敗(reject が呼ばれた) |
async / await(推奨)
ES2017 で追加された、Promise をより読みやすく書くための構文です。
// Promise チェーン(読みにくい)
fetchData()
.then(data => processData(data))
.then(result => displayResult(result))
.catch(error => handleError(error));
// async/await(読みやすい)
const main = async () => {
try {
const data = await fetchData();
const result = await processData(data);
displayResult(result);
} catch (error) {
handleError(error);
}
};
async 関数内で await を使うと、Promise が解決されるまで待ってから次の行に進みます。見た目は同期処理のように読めますが、実際には非同期です。
fetch API
fetch() は HTTP リクエストを送信するブラウザ標準の API です。
基本: GET リクエスト
const fetchUsers = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
const users = await response.json(); // JSONをパース
console.log(users);
};
fetchUsers();
レスポンスオブジェクト
const response = await fetch(url);
console.log(response.ok); // true(200-299)
console.log(response.status); // 200, 404, 500 など
console.log(response.headers); // レスポンスヘッダー
const json = await response.json(); // JSONとしてパース
const text = await response.text(); // テキストとして取得
const blob = await response.blob(); // バイナリ(画像など)
POST リクエスト
const createUser = async (userData) => {
const response = await fetch("https://jsonplaceholder.typicode.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
const newUser = await response.json();
console.log("作成されたユーザー:", newUser);
};
createUser({ name: "田中", email: "tanaka@example.com" });
HTTPメソッド一覧
| メソッド | 用途 |
|---|---|
GET |
データの取得 |
POST |
データの作成 |
PUT |
データの全体更新 |
PATCH |
データの一部更新 |
DELETE |
データの削除 |
実践: APIデータをページに表示する
ユーザー一覧の表示
<div id="userList"></div>
const displayUsers = async () => {
const container = document.querySelector("#userList");
container.textContent = "読み込み中...";
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);
const users = await response.json();
container.innerHTML = users.map(user => `
<div class="card">
<h3>${user.name}</h3>
<p>${user.email}</p>
<p>${user.company.name}</p>
</div>
`).join("");
} catch (error) {
container.textContent = `エラーが発生しました: ${error.message}`;
}
};
displayUsers();
注意: この例では innerHTML に API のデータを直接入れています。信頼できない API の場合は textContent で安全に表示してください。JSONPlaceholder は学習用のモック API なので、この例では問題ありません。
検索機能付き
const searchInput = document.querySelector("#search");
let allUsers = [];
const loadUsers = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
allUsers = await response.json();
renderUsers(allUsers);
};
const renderUsers = (users) => {
const container = document.querySelector("#userList");
if (users.length === 0) {
container.textContent = "該当するユーザーがいません";
return;
}
container.innerHTML = users.map(user => `
<div class="card">
<h3>${user.name}</h3>
<p>${user.email}</p>
</div>
`).join("");
};
searchInput.addEventListener("input", (e) => {
const query = e.target.value.toLowerCase();
const filtered = allUsers.filter(user =>
user.name.toLowerCase().includes(query) ||
user.email.toLowerCase().includes(query)
);
renderUsers(filtered);
});
loadUsers();
ローディング状態の管理
const fetchWithLoading = async (url) => {
const spinner = document.querySelector("#spinner");
const content = document.querySelector("#content");
const errorMsg = document.querySelector("#error");
spinner.style.display = "block";
content.style.display = "none";
errorMsg.style.display = "none";
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
content.style.display = "block";
return data;
} catch (error) {
errorMsg.textContent = error.message;
errorMsg.style.display = "block";
return null;
} finally {
spinner.style.display = "none"; // 成功でも失敗でも実行
}
};
複数のAPIを並列で呼ぶ
// 直列(遅い): 1つ完了してから次
const user = await fetch("/api/user").then(r => r.json());
const posts = await fetch("/api/posts").then(r => r.json());
// 合計時間 = user取得時間 + posts取得時間
// 並列(速い): 同時にリクエスト
const [user, posts] = await Promise.all([
fetch("/api/user").then(r => r.json()),
fetch("/api/posts").then(r => r.json()),
]);
// 合計時間 = max(user取得時間, posts取得時間)
Promise.all は渡したすべての Promise が完了するまで待ちます。1つでも失敗すると全体が失敗になります。
実践ワーク
- JSONPlaceholder API (
https://jsonplaceholder.typicode.com/posts) から投稿一覧を取得して表示 - ローディング中に「読み込み中...」を表示する
- 検索ボックスでタイトルのフィルタリングを実装
- 投稿をクリックすると詳細(
/posts/{id})を取得して表示
まとめと次回の準備
今回のポイント:
- 非同期処理: JavaScript はブロックせずに次へ進む
- async / await で非同期コードを読みやすく書く
- fetch() でAPI通信。response.json() でJSONパース
- try / catch でエラーハンドリング
- Promise.all で複数リクエストを並列実行
次回: エラー処理とデバッグ。バグを見つけて直す技術は、プログラミングで最も実用的なスキルです。
参考文献: - MDN Web Docs「async function」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function) - MDN Web Docs「Fetch API」(https://developer.mozilla.org/ja/docs/Web/API/Fetch_API) - JSONPlaceholder(https://jsonplaceholder.typicode.com/)— 学習用無料API
Lecture 9エラー処理とデバッグ — バグを見つけて直す技術
10:00
エラー処理とデバッグ — バグを見つけて直す技術
エラーの種類
JavaScript のエラーは大きく3種類に分けられます。
1. 構文エラー(SyntaxError)
コードの書き方が間違っている。実行前にブラウザが検出。
// 括弧の閉じ忘れ
if (x > 5 { // SyntaxError: Unexpected token '{'
console.log("OK");
}
// クォートの閉じ忘れ
const name = "田中; // SyntaxError: Invalid or unexpected token
2. 実行時エラー(RuntimeError)
実行中に発生するエラー。
// 存在しない変数の参照
console.log(userName); // ReferenceError: userName is not defined
// 関数でないものを呼び出し
const x = 5;
x(); // TypeError: x is not a function
// nullのプロパティにアクセス
const user = null;
console.log(user.name); // TypeError: Cannot read properties of null
3. 論理エラー(Logic Error)
エラーは出ないが、結果が間違っている。最も発見しにくい。
// 意図: 平均を計算
const average = (a, b) => a + b / 2; // NG: 演算子の優先順位
// average(10, 20) → 10 + 10 = 20(正解は15)
const average = (a, b) => (a + b) / 2; // OK
// average(10, 20) → 15
よくあるエラーと対処法
| エラー | 原因 | 対処 |
|---|---|---|
TypeError: Cannot read properties of undefined |
未定義のプロパティにアクセス | オプショナルチェイニング ?. を使う |
ReferenceError: x is not defined |
変数名のタイプミス、スコープ外 | スペルを確認、変数の宣言位置を確認 |
TypeError: x is not a function |
関数でないものを呼んでいる | 変数名の衝突を確認 |
SyntaxError: Unexpected token |
括弧やカンマの過不足 | エディタの括弧マッチング機能を使う |
RangeError: Maximum call stack |
無限再帰 | 再帰の終了条件を確認 |
try / catch / finally
const parseJSON = (jsonString) => {
try {
const data = JSON.parse(jsonString);
return data;
} catch (error) {
console.error("JSONのパースに失敗:", error.message);
return null;
} finally {
console.log("パース処理が完了しました"); // 成功・失敗どちらでも実行
}
};
console.log(parseJSON('{"name": "田中"}')); // { name: "田中" }
console.log(parseJSON('不正なJSON')); // null
カスタムエラーを投げる
const validateAge = (age) => {
if (typeof age !== "number") {
throw new TypeError("年齢は数値で入力してください");
}
if (age < 0 || age > 150) {
throw new RangeError("年齢は0〜150の範囲で入力してください");
}
return true;
};
try {
validateAge("二十歳");
} catch (error) {
console.error(`${error.name}: ${error.message}`);
// TypeError: 年齢は数値で入力してください
}
Chrome DevTools でデバッグ
Console(基本)
console.log("一般的な出力");
console.warn("警告");
console.error("エラー");
console.table([{ name: "田中", age: 30 }, { name: "鈴木", age: 25 }]);
console.time("処理時間");
// ... 処理 ...
console.timeEnd("処理時間"); // "処理時間: 15.2ms"
console.group("ユーザー情報");
console.log("名前: 田中");
console.log("年齢: 30");
console.groupEnd();
ブレークポイント(最強のデバッグツール)
- F12 → Sources タブ
- 左パネルでJSファイルを選択
- 行番号をクリックしてブレークポイントを設定(青い印が付く)
- ページを操作してその行が実行されると、実行が一時停止する
- 右パネルで変数の値を確認できる
ステップ実行
ブレークポイントで停止中に:
| ボタン | 動作 | ショートカット |
|---|---|---|
| Resume | 次のブレークポイントまで実行 | F8 |
| Step Over | 1行ずつ実行(関数内に入らない) | F10 |
| Step Into | 関数の中に入って実行 | F11 |
| Step Out | 現在の関数から抜ける | Shift+F11 |
debugger 文
コードに debugger を書くと、DevTools が開いている場合にそこで一時停止します。
const calculate = (a, b) => {
debugger; // ここで停止
const result = a * b;
return result;
};
本番環境にデプロイする前に debugger を削除してください。
Watch(変数の監視)
Sources パネルの右側「Watch」に変数名を追加すると、ステップ実行中にその変数の値をリアルタイムで確認できます。
デバッグの手順
- 再現: バグが起きる操作を特定する
- 仮説: 「この部分が原因ではないか」と仮説を立てる
- 確認:
console.logやブレークポイントで値を確認 - 修正: 原因を修正
- 検証: バグが直ったか確認。他の部分に影響がないかも確認
二分探索デバッグ
どこでバグが起きているかわからない場合:
- コードの真ん中に
console.log("ここまでOK")を挿入 - 表示されれば前半は正常 → 後半を同様に二分割
- 表示されなければ前半に問題 → 前半を同様に二分割
- 問題の行を特定するまで繰り返す
防御的プログラミング
入力の検証
const greet = (name) => {
if (typeof name !== "string" || name.trim() === "") {
return "名前が不正です";
}
return `こんにちは、${name}さん!`;
};
デフォルト値
const getConfig = (options = {}) => {
const config = {
theme: "light",
lang: "ja",
fontSize: 16,
...options,
};
return config;
};
console.log(getConfig({ theme: "dark" }));
// { theme: "dark", lang: "ja", fontSize: 16 }
早期リターン(ガード節)
// NG: ネストが深い
const processUser = (user) => {
if (user) {
if (user.isActive) {
if (user.age >= 18) {
// 処理
}
}
}
};
// OK: ガード節で早期リターン
const processUser = (user) => {
if (!user) return;
if (!user.isActive) return;
if (user.age < 18) return;
// 処理
};
実践ワーク
- Chrome DevTools の Sources タブでブレークポイントを設定し、変数の値を確認する
- 意図的にバグを含むコードを書き、Console のエラーメッセージから原因を特定して修正する:
// 以下のコードにはバグが3つあります。見つけて修正してください
const calcDiscount = (price, discountRate) => {
if (price < 0) {
console.log("価格が不正です");
}
const discounted = price * discountRate;
return Mathfloor(discounted);
};
const items = ["りんご", "バナナ", "オレンジ"];
console.log(items[3].toUpperCase());
const user = { name: "田中" };
console.log(user.address.city);
まとめと次回の準備
今回のポイント:
- エラーの3種類: 構文エラー、実行時エラー、論理エラー
- try / catch でエラーを捕捉し、アプリのクラッシュを防ぐ
- Chrome DevTools のブレークポイントが最強のデバッグツール
- console.log だけでなく console.table, console.time も活用
- 防御的プログラミング: 入力検証、デフォルト値、ガード節
次回(最終回): これまでの全スキルを統合して、ToDo アプリを1から作り上げます。
参考文献: - MDN Web Docs「エラーハンドリング」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#exception_handling_statements) - Google「Chrome DevTools でデバッグする」(https://developer.chrome.com/docs/devtools/javascript/) - MDN Web Docs「Console API」(https://developer.mozilla.org/ja/docs/Web/API/console)
Lecture 10総合演習 — ToDoアプリを作ろう
15:00
総合演習 — ToDoアプリを作ろう
この講座で学んだスキルの全体像
9つの講義を通じて、JavaScript の基礎から実践までを学びました。最終回では、すべてのスキルを統合して ToDo アプリ を完成させます。
| 講義 | 学んだスキル | 本演習での活用 |
|---|---|---|
| 第1回 | JavaScript の基本、Console | 開発環境 |
| 第2回 | 変数、データ型、演算子 | データの管理 |
| 第3回 | 条件分岐、ループ | フィルタリング、描画 |
| 第4回 | 関数、アロー関数、配列メソッド | すべての処理を関数化 |
| 第5回 | 配列、オブジェクト、JSON | ToDo データの管理 |
| 第6回 | DOM操作 | 画面の描画と更新 |
| 第7回 | イベント処理 | クリック、入力、キーボード |
| 第8回 | 非同期処理、API | localStorage で永続化 |
| 第9回 | エラー処理、デバッグ | 入力バリデーション |
完成イメージの機能
- タスクの追加: テキスト入力 + 追加ボタン(Enter キーでも追加可)
- タスクの完了: チェックボックスで完了/未完了を切り替え
- タスクの削除: 削除ボタンでタスクを削除
- フィルター: すべて / 未完了 / 完了済み
- 残タスク数の表示: 未完了のタスク数をリアルタイム表示
- 永続化: localStorage でブラウザを閉じてもデータが残る
ファイル構造
todo-app/
├── index.html
├── css/
│ └── style.css
└── js/
└── app.js
Step 1: HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDo App</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="app">
<h1>ToDo App</h1>
<!-- 入力エリア -->
<div class="input-area">
<input type="text" id="todoInput" placeholder="タスクを入力..." autofocus>
<button id="addBtn">追加</button>
</div>
<!-- フィルター -->
<div class="filters">
<button class="filter-btn active" data-filter="all">すべて</button>
<button class="filter-btn" data-filter="active">未完了</button>
<button class="filter-btn" data-filter="completed">完了済み</button>
</div>
<!-- タスクリスト -->
<ul id="todoList"></ul>
<!-- ステータスバー -->
<div class="status-bar">
<span id="taskCount">0個のタスク</span>
<button id="clearCompleted">完了済みを削除</button>
</div>
</div>
<script src="js/app.js"></script>
</body>
</html>
Step 2: CSS
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--color-primary: #6366f1;
--color-primary-dark: #4f46e5;
--color-bg: #f1f5f9;
--color-card: #ffffff;
--color-text: #1e293b;
--color-text-light: #94a3b8;
--color-border: #e2e8f0;
--color-danger: #ef4444;
--color-success: #22c55e;
--radius: 8px;
}
body {
font-family: "Segoe UI", "Noto Sans JP", sans-serif;
background-color: var(--color-bg);
color: var(--color-text);
min-height: 100vh;
display: flex;
justify-content: center;
padding: 40px 16px;
}
.app {
width: 100%;
max-width: 520px;
}
h1 {
text-align: center;
font-size: 2rem;
margin-bottom: 24px;
color: var(--color-primary);
}
/* 入力エリア */
.input-area {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
.input-area input {
flex: 1;
padding: 12px 16px;
border: 2px solid var(--color-border);
border-radius: var(--radius);
font-size: 1rem;
transition: border-color 0.2s;
}
.input-area input:focus {
outline: none;
border-color: var(--color-primary);
}
.input-area button {
padding: 12px 24px;
background-color: var(--color-primary);
color: white;
border: none;
border-radius: var(--radius);
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background-color 0.2s;
}
.input-area button:hover {
background-color: var(--color-primary-dark);
}
/* フィルター */
.filters {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
.filter-btn {
flex: 1;
padding: 8px;
background: var(--color-card);
border: 1px solid var(--color-border);
border-radius: var(--radius);
cursor: pointer;
font-size: 0.875rem;
transition: all 0.2s;
}
.filter-btn.active {
background-color: var(--color-primary);
color: white;
border-color: var(--color-primary);
}
/* タスクリスト */
#todoList {
list-style: none;
}
.todo-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background: var(--color-card);
border-radius: var(--radius);
margin-bottom: 8px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
transition: opacity 0.2s;
}
.todo-item.completed .todo-text {
text-decoration: line-through;
color: var(--color-text-light);
}
.todo-item input[type="checkbox"] {
width: 20px;
height: 20px;
cursor: pointer;
accent-color: var(--color-success);
}
.todo-text {
flex: 1;
font-size: 1rem;
}
.delete-btn {
background: none;
border: none;
color: var(--color-text-light);
font-size: 1.25rem;
cursor: pointer;
padding: 4px 8px;
border-radius: 4px;
transition: all 0.2s;
}
.delete-btn:hover {
color: var(--color-danger);
background-color: #fef2f2;
}
/* ステータスバー */
.status-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
font-size: 0.875rem;
color: var(--color-text-light);
}
#clearCompleted {
background: none;
border: none;
color: var(--color-text-light);
cursor: pointer;
font-size: 0.875rem;
}
#clearCompleted:hover {
color: var(--color-danger);
text-decoration: underline;
}
/* 空状態 */
.empty-message {
text-align: center;
padding: 32px;
color: var(--color-text-light);
}
Step 3: JavaScript
// ========================================
// 状態管理
// ========================================
// localStorageからタスクを読み込み(永続化)
const loadTodos = () => {
try {
const stored = localStorage.getItem("todos");
return stored ? JSON.parse(stored) : [];
} catch {
return [];
}
};
// localStorageに保存
const saveTodos = (todos) => {
localStorage.setItem("todos", JSON.stringify(todos));
};
// アプリの状態
let todos = loadTodos();
let currentFilter = "all";
// ========================================
// DOM要素の取得
// ========================================
const todoInput = document.querySelector("#todoInput");
const addBtn = document.querySelector("#addBtn");
const todoList = document.querySelector("#todoList");
const taskCount = document.querySelector("#taskCount");
const clearCompletedBtn = document.querySelector("#clearCompleted");
const filterBtns = document.querySelectorAll(".filter-btn");
// ========================================
// タスクの操作(データ層)
// ========================================
const addTodo = (text) => {
const trimmed = text.trim();
if (trimmed === "") return;
const newTodo = {
id: Date.now(), // 一意のID(タイムスタンプ)
text: trimmed,
completed: false,
createdAt: new Date().toISOString(),
};
todos.push(newTodo);
saveTodos(todos);
render();
};
const toggleTodo = (id) => {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
saveTodos(todos);
render();
}
};
const deleteTodo = (id) => {
todos = todos.filter(t => t.id !== id);
saveTodos(todos);
render();
};
const clearCompleted = () => {
todos = todos.filter(t => !t.completed);
saveTodos(todos);
render();
};
// ========================================
// フィルタリング
// ========================================
const getFilteredTodos = () => {
switch (currentFilter) {
case "active":
return todos.filter(t => !t.completed);
case "completed":
return todos.filter(t => t.completed);
default:
return todos;
}
};
// ========================================
// 描画(UI層)
// ========================================
const render = () => {
const filtered = getFilteredTodos();
// タスクリストの描画
if (filtered.length === 0) {
todoList.innerHTML = '<li class="empty-message">タスクがありません</li>';
} else {
todoList.innerHTML = filtered.map(todo => `
<li class="todo-item ${todo.completed ? "completed" : ""}" data-id="${todo.id}">
<input type="checkbox" ${todo.completed ? "checked" : ""}>
<span class="todo-text">${escapeHTML(todo.text)}</span>
<button class="delete-btn" aria-label="削除">×</button>
</li>
`).join("");
}
// 残タスク数の更新
const activeCount = todos.filter(t => !t.completed).length;
taskCount.textContent = `${activeCount}個の未完了タスク`;
// フィルターボタンのアクティブ状態
filterBtns.forEach(btn => {
btn.classList.toggle("active", btn.dataset.filter === currentFilter);
});
};
// XSS対策: HTMLエスケープ
const escapeHTML = (str) => {
const div = document.createElement("div");
div.textContent = str;
return div.innerHTML;
};
// ========================================
// イベントリスナー
// ========================================
// 追加ボタン
addBtn.addEventListener("click", () => {
addTodo(todoInput.value);
todoInput.value = "";
todoInput.focus();
});
// Enterキーで追加
todoInput.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
addTodo(todoInput.value);
todoInput.value = "";
}
});
// タスクリスト(イベント委任)
todoList.addEventListener("click", (e) => {
const item = e.target.closest(".todo-item");
if (!item) return;
const id = Number(item.dataset.id);
// チェックボックス
if (e.target.type === "checkbox") {
toggleTodo(id);
}
// 削除ボタン
if (e.target.classList.contains("delete-btn")) {
deleteTodo(id);
}
});
// フィルターボタン
filterBtns.forEach(btn => {
btn.addEventListener("click", () => {
currentFilter = btn.dataset.filter;
render();
});
});
// 完了済みを削除
clearCompletedBtn.addEventListener("click", clearCompleted);
// ========================================
// 初期描画
// ========================================
render();
コードの解説
設計のポイント
- データとUIの分離:
todos配列(データ)とrender()関数(UI)を分離。データを変更したらrender()を呼ぶだけでUIが更新される - イベント委任:
todoListに1つだけイベントリスナーを付けて、動的に追加されるアイテムにも対応 - XSSエスケープ:
escapeHTML()でユーザー入力をサニタイズ - localStorage:
JSON.stringify/JSON.parseでデータを永続化 Date.now()でID生成: 簡易的な一意ID(本格的なアプリではUUIDを使う)
localStorage の補足
// 保存
localStorage.setItem("key", "value");
// 取得
const value = localStorage.getItem("key");
// 削除
localStorage.removeItem("key");
// 全削除
localStorage.clear();
localStorage はブラウザに文字列としてデータを保存します。オブジェクトや配列は JSON.stringify() で文字列に変換してから保存し、JSON.parse() で復元します。
注意: localStorage は約 5MB の容量制限があり、同じオリジン(ドメイン)内で共有されます。機密データの保存には使わないでください。
機能拡張のアイデア
| 機能 | 使う技術 |
|---|---|
| ドラッグ&ドロップで並べ替え | HTML Drag and Drop API |
| タスクの編集(ダブルクリック) | イベント処理 + DOM操作 |
| 期限の設定 | <input type="date"> + Date |
| カテゴリ / タグ | オブジェクトにプロパティ追加 |
| ダークモード | classList.toggle("dark") + CSS変数 |
| API連携(クラウド保存) | fetch() + バックエンドAPI |
この講座の振り返りと次のステップ
学んだこと
文法: 変数、データ型、演算子、条件分岐、ループ、関数、配列、オブジェクト
DOM: 要素の取得・変更・作成・削除、イベント処理、イベント委任
非同期: Promise, async/await, fetch API
実践: エラー処理、デバッグ、XSS対策、localStorage
さらに学びたい方へ
| 方向性 | 内容 | リソース |
|---|---|---|
| フレームワーク | React, Vue.js, Svelte | 各公式ドキュメント |
| TypeScript | 型安全な JavaScript | typescriptlang.org |
| Node.js | サーバーサイド JavaScript | nodejs.org |
| テスト | Jest, Vitest | 各公式ドキュメント |
| Web API | Canvas, Web Audio, WebSocket | MDN Web Docs |
最後に
JavaScript はブラウザさえあれば誰でも始められる、最もアクセスしやすいプログラミング言語です。そして、フロントエンド、バックエンド、モバイルアプリ、デスクトップアプリ、ゲーム開発まで、あらゆる領域で使われています。
この講座で作った ToDo アプリは小さなアプリですが、データ管理、UI描画、イベント処理、永続化という Web アプリの基本構造 がすべて含まれています。ここから先、React や Vue.js などのフレームワークを学ぶ際も、この基礎が確実に役立ちます。
「動くものを作る」ことが最大の学習です。 次は自分のアイデアでアプリを作ってみてください。
参考文献: - MDN Web Docs「JavaScript ガイド」(https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide) - MDN Web Docs「Web Storage API」(https://developer.mozilla.org/ja/docs/Web/API/Web_Storage_API) - javascript.info(https://ja.javascript.info/)— 無料の包括的チュートリアル