コンテンツにスキップ

8-2. 制御フロー・関数・スコープ

  • if/elseswitch・三項演算子・ループなどの制御フローを書けるようになる
  • 関数宣言・関数式・アロー関数の違いと使い分けを理解する
  • デフォルト引数・残余引数・コールバックなど関数の応用を知る
  • スコープ(グローバル・関数・ブロック)のルールを理解する
  • クロージャの仕組みと実用パターンを学ぶ

const score = 75;
if (score >= 90) {
console.log("");
} else if (score >= 70) {
console.log(""); // ← これが実行される
} else if (score >= 60) {
console.log("");
} else {
console.log("不可");
}

複数の値に対して分岐するときは switch が読みやすい。break を忘れると次のケースに「フォールスルー」する点に注意。

const day = "Monday";
switch (day) {
case "Saturday":
case "Sunday":
console.log("休日");
break;
case "Monday":
console.log("週明け"); // ← これが実行される
break;
default:
console.log("平日");
}

if/else を1行で書きたいときに使う。ネストは避ける。

const age = 20;
const label = age >= 18 ? "成人" : "未成年";
// ネストは避ける(読みにくい)
// const label = age >= 18 ? (age >= 65 ? "高齢者" : "成人") : "未成年";
// 基本的なforループ
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// while
let count = 0;
while (count < 3) {
console.log(count);
count++;
}
// 配列のループは for...of が推奨(インデックスが不要な場合)
const fruits = ["apple", "banana", "cherry"];
for (const fruit of fruits) {
console.log(fruit);
}
// オブジェクトのキーをループするには for...in
const obj = { a: 1, b: 2, c: 3 };
for (const key in obj) {
console.log(key, obj[key]);
}
// break:ループを抜ける
for (let i = 0; i < 10; i++) {
if (i === 5) break;
console.log(i); // 0〜4
}
// continue:その回のループをスキップして次へ
for (let i = 0; i < 5; i++) {
if (i === 2) continue;
console.log(i); // 0, 1, 3, 4
}

// 関数宣言:ホイスティング(巻き上げ)が起きる
greet("Alice"); // エラーなし(宣言前に呼べる)
function greet(name) {
return `こんにちは、${name}`;
}
// 関数式:変数に関数を代入する
const greet2 = function(name) {
return `こんにちは、${name}`;
};
greet2("Bob");

ES6で導入された短い書き方。現代のコードではアロー関数が主流。

// 通常の関数
const double = function(n) { return n * 2; };
// アロー関数
const double2 = (n) => { return n * 2; };
// 引数が1つのとき括弧を省略できる
const double3 = n => { return n * 2; };
// 関数本体が return 式だけのとき { } と return を省略できる
const double4 = n => n * 2;
// 引数なし
const sayHello = () => "Hello!";
// オブジェクトを返すときは () で囲む({} がブロックと区別がつかないため)
const makeUser = name => ({ name, active: true });

アロー関数と通常の関数の最大の違いは this の扱いだ。アロー関数は this を持たず、外のスコープの this を引き継ぐ。DOM操作やコールバックで重要になるので、第10章のフロントエンド実装で詳しく扱う。

// デフォルト引数
function createUser(name, role = "user", active = true) {
return { name, role, active };
}
createUser("Alice") // { name: "Alice", role: "user", active: true }
createUser("Bob", "admin") // { name: "Bob", role: "admin", active: true }
// 残余引数(...args):可変長引数を配列で受け取る
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3, 4, 5) // 15

関数は「第一級オブジェクト」

Section titled “関数は「第一級オブジェクト」”

JavaScriptでは関数を変数に代入したり、他の関数の引数として渡したり、戻り値として返したりできる。

// 関数を引数に渡す(コールバック)
function runTwice(fn) {
fn();
fn();
}
runTwice(() => console.log("実行!")); // "実行!" が2回出力
// 関数を返す(クロージャ)
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
counter() // 1
counter() // 2
counter() // 3

スコープとは「変数がどこから見えるか」のルールだ。

スコープの種類
┌──────────────────────────────────────────────┐
│ グローバルスコープ │
│ ┌───────────────────────────────────────┐ │
│ │ モジュールスコープ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ 関数スコープ │ │ │
│ │ │ ┌─────────────────────┐ │ │ │
│ │ │ │ ブロックスコープ({})│ │ │ │
│ │ │ └─────────────────────┘ │ │ │
│ │ └──────────────────────────────┘ │ │
│ └───────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
const global = "グローバル";
function outer() {
const outerVar = "";
function inner() {
const innerVar = "";
console.log(global); // OK:上のスコープの変数は見える
console.log(outerVar); // OK:クロージャ
console.log(innerVar); // OK:自分のスコープ
}
inner();
console.log(innerVar); // エラー:内側の変数は外から見えない
}
// let/const はブロック {} の中だけ有効
{
let x = 10;
const y = 20;
}
console.log(x); // エラー:x is not defined
// if/for の {} も同様
if (true) {
let temp = "一時変数";
}
console.log(temp); // エラー
// var はブロックを無視して関数スコープになる(古い挙動)
if (true) {
var old = "古い書き方";
}
console.log(old); // "古い書き方"(漏れる!)

内側の関数が外側の変数を「閉じ込める」現象をクロージャと呼ぶ。モジュールパターンやカウンターの実装に使われる。

function makeMultiplier(factor) {
// factor は makeMultiplier の引数だが、
// 返す関数がこれを参照し続ける
return n => n * factor;
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);
double(5) // 10
triple(5) // 15

クロージャの仕組み:

makeMultiplier(2) を呼ぶ
└── factor = 2 のスコープが生まれる
└── n => n * factor という関数がそのスコープを「閉じ込めて」返る
└── double(5) を呼ぶと factor = 2 がまだ生きている → 10

項目ポイント
制御フローif/elseswitch・三項演算子を使い分ける
関数定義アロー関数が主流。this の扱いに注意
デフォルト引数引数の省略時のデフォルト値を関数定義で指定できる
スコープlet/const はブロックスコープ。内側から外側は見えるが逆は不可
クロージャ外側スコープの変数を内側の関数が参照し続ける仕組み