JavaScript / LESSON 08 / JS08

JavaScript:関数とアロー関数

1学習の目的

2基礎解説

やりたいこと書き方備考
関数を作るfunction add(a, b) { }従来の書き方
短く書くconst add = (a, b) => a + b;アロー関数。return 省略可
省略できる引数(price, rate = 0.1) =>渡さなければ既定値
複数の値を返すreturn [total, best];const [t, b] = f();
✅ 覚えるべき重要ポイント
  1. console.log と return は別物。log は画面に出すだけ、return は値を呼び出し元に渡す。計算結果を後で使うなら return。
  2. return を書かない関数の戻り値は undefinedconst r = f(5); が undefined になる事故はほぼこれが原因。
  3. アロー関数は本体が式1つなら { } と return を省略できるn => n * 2 のように書ける。引数が1つならカッコも省略可。
  4. アロー関数は定義より前で呼べないfunction 宣言は前でも呼べる(巻き上げ)が、この違いに頼らず使う前に定義するのが安全。
  5. 関数の中で作った変数は外から見えない(スコープ)。外へ渡したいときは必ず return する。

現場使用例:税込計算 withTax(price)、入力チェック validate(name)、データ整形 formatRow(row)。同じ処理を複数の画面で使い回すときは必ず関数にする。

// 従来の書き方
function greet(name) {
  return `こんにちは、${name}さん`;
}

// アロー関数(式1つなら return を省略できる)
const add = (a, b) => a + b;
const double = n => n * 2;

console.log(greet("田中"));   // こんにちは、田中さん
console.log(add(3, 7));       // 10
console.log(double(5));       // 10

// 既定値つき引数
const withTax = (price, rate = 0.1) => Math.round(price * (1 + rate));

console.log(withTax(1000));        // 1100
console.log(withTax(1000, 0.08));  // 1080

// 複数の値を返す
const stats = nums => [Math.max(...nums), nums.length];

const [max, count] = stats([3, 9, 5]);
console.log(max, count);      // 9 3

3基本ドリル(10問)

JS08-D01 名前を受け取って「こんにちは、田中さん」という文字列を返す関数 greet を作り、"田中" で呼び出した結果を出力せよ。 コーディング★☆☆無料
期待される結果

出力 == こんにちは、田中さん

ヒント

function greet(name) { return ... } の中で return する。呼び出しは console.log(greet("田中"))。

模範解答
function greet(name) {
  return `こんにちは、${name}さん`;
}

console.log(greet("田中"));
解説

関数の最小形。定義しただけでは何も起きず、呼び出して初めて動く

JS08-D02 return を1行も書かない関数を呼び出したとき、戻り値は何になるか。
A. 0 B. 空文字 C. undefined D. エラー
選択★☆☆無料
期待される結果

解答 == C

ヒント

「何も返さない」をJavaScriptはどう表すか。

模範解答
C
解説

戻り値なし=undefined。この undefined が後の計算に混ざって NaN を生むのが典型的なバグの連鎖。

JS08-D03 2つの数を受け取って合計を返す関数 add をアロー関数で定義し、add(3, 7) の結果を出力せよ。 コーディング★☆☆無料
期待される結果

出力 == 10

ヒント

const add = (a, b) => a + b; と書く。式1つなので { } と return は不要。

模範解答
const add = (a, b) => a + b;

console.log(add(3, 7));
解説

アロー関数は矢印 => の右に式を書くだけで、その値が自動的に返る。1行で書ける処理はこの形が読みやすい。

JS08-D04 長方形の面積を返す関数を完成させよ。 穴埋め★☆☆無料
コード
function area(w, h) {
  ____ w * h;
}

console.log(area(3, 4));
期待される結果

出力 == 12

ヒント

計算結果を呼び出し元へ渡すキーワード。

模範解答
return
解説

ここを console.log にすると画面には12が出るが、関数の戻り値は undefined になる。使い回すなら return。

JS08-D05 const f = x => { console.log(x * 2); }; として const r = f(5); としたとき r の中身はどれか。
A. 10 B. undefined C. 5 D. エラー
選択★☆☆無料
期待される結果

解答 == B

ヒント

画面に出ることと、値が返ることは同じか?

模範解答
B
解説

画面には10が出るが return が無いので r は undefined。{ } を書いた場合は return を省略できない点にも注意。

JS08-D06 価格と税率を受け取り、税込価格(Math.round で整数化)を返す関数 withTax をアロー関数で定義せよ。税率は省略時 0.1 とする。withTax(1000) と withTax(1000, 0.08) の結果を2行で出力すること。 コーディング★★☆無料
期待される結果

出力 == 1100 / 1080(2行)

ヒント

const withTax = (price, rate = 0.1) => Math.round(price * (1 + rate)); と書く。

模範解答
const withTax = (price, rate = 0.1) => Math.round(price * (1 + rate));

console.log(withTax(1000));
console.log(withTax(1000, 0.08));
解説

既定値つき引数は「ほとんどの場合は同じ値、たまに変えたい」場面に最適。既定値のある引数は後ろに置くのが原則。

JS08-D07 数値を2倍にして返すアロー関数を完成させよ。 穴埋め★★☆無料
コード
const double = n ____ n * 2;

console.log(double(5));
期待される結果

出力 == 10

ヒント

アロー関数の矢印。イコールと大なり記号の組み合わせ。

模範解答
=>
解説

引数が1つならカッコも省略できる。(n) => n * 2 と書いても同じ。

JS08-D08 関数の中で const total = 100; と宣言した。関数の外で console.log(total) するとどうなるか。
A. 100が出る B. ReferenceErrorになる C. undefinedが出る D. 0が出る
選択★★☆無料
期待される結果

解答 == B

ヒント

関数の中で作った変数はどこまで生きているか。

模範解答
B
解説

関数内の変数は関数を抜けると消える(スコープ)。外へ持ち出したければ return するのが唯一の正攻法。

JS08-D09 配列を受け取り、合計と最大値の2つを返す関数 stats を定義し、[3, 9, 5] で呼び出して「合計17 最大9」の形式で出力せよ。 コーディング★★☆無料
期待される結果

出力 == 合計17 最大9

ヒント

配列で返す。受け取りは const [total, max] = stats(...) と分割代入する。

模範解答
const stats = nums => {
  let total = 0;
  for (const n of nums) {
    total += n;
  }
  return [total, Math.max(...nums)];
};

const [total, max] = stats([3, 9, 5]);
console.log(`合計${total} 最大${max}`);
解説

配列で返して分割代入で受け取るのが2値を返す定番。項目が増えるなら { total, max } とオブジェクトで返すほうが順序を気にせず済む。

JS08-D10 点数を受け取り、60以上なら「合格」、未満なら「不合格」を返す関数 judge をアロー関数で定義し、judge(72) と judge(45) の結果を2行で出力せよ。 コーディング★★☆無料
期待される結果

出力 == 合格 / 不合格(2行)

ヒント

三項演算子を使えば1行で書ける。

模範解答
const judge = score => (score >= 60 ? "合格" : "不合格");

console.log(judge(72));
console.log(judge(45));
解説

JS04の条件分岐を関数に閉じ込めた形。判定ロジックを1箇所にまとめておけば、基準が変わってもここだけ直せばよい

4実践シナリオ(5問)

JS08-S01 【送料計算の部品化】購入額を受け取り、5,000円以上なら0、未満なら600を返す関数 shippingFee を定義せよ。そのうえで [4800, 5000, 12000] の3件を「4,800円 → 送料600円」の形式で出力せよ。 コーディング★★☆無料
期待される結果

3行。4,800円 → 送料600円 ほか

ヒント

関数を定義してから for...of で回す。テンプレートリテラルの中で shippingFee(p) を直接呼べる。

模範解答
const shippingFee = price => (price >= 5000 ? 0 : 600);

for (const p of [4800, 5000, 12000]) {
  console.log(`${p.toLocaleString()}円 → 送料${shippingFee(p)}円`);
}
解説

JS04で書いた送料判定を関数にした形。ループの中で関数を呼ぶと、判定ロジックとループが分離されて読みやすくなる。

JS08-S02 【BMI判定の関数化】身長(m)と体重(kg)を受け取り、BMI(小数1桁)と判定をオブジェクトで返す関数 bmiCheck を定義せよ。判定は25以上「肥満」、18.5未満「痩せ」、その他「標準」。(1.72, 78) で呼び出し「BMI:26.4 → 肥満」の形式で出力すること。 コーディング★★☆無料
期待される結果

出力 == BMI:26.4 → 肥満

ヒント

return { bmi, judge } のように返し、const { bmi, judge } = bmiCheck(...) で受け取る。小数1桁は toFixed(1)。

模範解答
const bmiCheck = (height, weight) => {
  const value = weight / height ** 2;

  let judge;
  if (value >= 25) {
    judge = "肥満";
  } else if (value < 18.5) {
    judge = "痩せ";
  } else {
    judge = "標準";
  }

  return { bmi: value.toFixed(1), judge };
};

const { bmi, judge } = bmiCheck(1.72, 78);
console.log(`BMI:${bmi} → ${judge}`);
解説

オブジェクトで返すと受け取り側が順序を気にしなくてよい。JS07の分割代入がここで活きる。項目が3つ以上になったら配列よりオブジェクトが安全。

JS08-S03 【入力チェックの関数化】名前とパスワードを受け取り、名前が空なら「名前を入力してください」、パスワードが8文字未満なら「パスワードは8文字以上にしてください」、どちらも問題なければ「OK」を返す関数 validate を定義せよ。("", "abc123")、("田中", "abc123")、("田中", "abcd1234") の3通りを順に出力すること。 コーディング★★☆無料
期待される結果

出力3行が完全一致

ヒント

エラー条件を先に書いて即 return すると、else を書かずに済む。

模範解答
const validate = (name, password) => {
  if (!name) {
    return "名前を入力してください";
  }

  if (password.length < 8) {
    return "パスワードは8文字以上にしてください";
  }

  return "OK";
};

console.log(validate("", "abc123"));
console.log(validate("田中", "abc123"));
console.log(validate("田中", "abcd1234"));
解説

早期リターンという書き方。return はその場で関数を抜けるので、else や入れ子の if が消えて一気に読みやすくなる。実務のバリデーションはほぼこの形。

JS08-S04 【割引価格の関数化】価格・会員かどうか・クーポンの有無を受け取り、支払額を返す関数 finalPrice を定義せよ。会員なら10%引き(Math.round)、クーポンがあればさらに500円引き、結果がマイナスなら0とする。会員フラグとクーポンは省略時 false
finalPrice(12000, true, false) / finalPrice(12000) / finalPrice(400, false, true) の3通りを「12,000円 → 10,800円」の形式で出力せよ。
コーディング★★★無料
期待される結果

出力3行が完全一致

ヒント

const finalPrice = (price, isMember = false, hasCoupon = false) => { ... } と定義する。中身はJS04の割引計算と同じ。

模範解答
const finalPrice = (price, isMember = false, hasCoupon = false) => {
  let total = price;

  if (isMember) {
    total = Math.round(total * 0.9);
  }

  if (hasCoupon) {
    total -= 500;
  }

  if (total < 0) {
    total = 0;
  }

  return total;
};

console.log(`12,000円 → ${finalPrice(12000, true, false).toLocaleString()}円`);
console.log(`12,000円 → ${finalPrice(12000).toLocaleString()}円`);
console.log(`400円 → ${finalPrice(400, false, true).toLocaleString()}円`);
解説

既定値を false にしておくと「普通の客なら引数1つで呼べる」関数になる。よくある呼び方を短く書けるようにするのが良い関数設計。

JS08-S05 【集計関数の使い回し】点数の配列を受け取り、平均・最高点・合格者数(60点以上)をオブジェクトで返す関数 summarize を定義せよ。classA = [82, 45, 91, 68]、classB = [70, 55, 88] の2クラスに同じ関数を使い、「A組 → 平均71.5点 / 最高91点 / 合格3人」の形式で2行出力すること。 コーディング★★★無料
期待される結果

出力2行が完全一致

ヒント

return { average, max, passed } で3つ返す。2クラスは [["A組", classA], ["B組", classB]] の配列で回すとループ1本で書ける。平均は toFixed(1)。

模範解答
const summarize = scores => {
  let total = 0;
  let passed = 0;

  for (const s of scores) {
    total += s;
    if (s >= 60) {
      passed++;
    }
  }

  return {
    average: (total / scores.length).toFixed(1),
    max: Math.max(...scores),
    passed,
  };
};

const classA = [82, 45, 91, 68];
const classB = [70, 55, 88];

for (const [name, scores] of [["A組", classA], ["B組", classB]]) {
  const { average, max, passed } = summarize(scores);
  console.log(`${name} → 平均${average}点 / 最高${max}点 / 合格${passed}人`);
}
解説

同じ関数を違うデータに何度でも使えるのが関数化の最大の利点。クラスが10個に増えてもコードは1行も増えない。passed, のように変数名とキー名が同じなら省略記法が使える点も覚えておきたい。

5仕上げ課題

JS08-FINAL 【請求書作成スクリプト】3つの関数を定義し、組み合わせて請求書を出力せよ。

const items = [
 { name: "ノートPC", price: 128000, qty: 1 },
 { name: "マウス", price: 3200, qty: 2 },
 { name: "USBメモリ", price: 1500, qty: 3 },
];
const isMember = true;


定義する関数(すべてアロー関数で):
subtotal(item) … 明細1件の小計(単価×数量)を返す
applyDiscount(amount, isMember) … 会員なら10%引き(Math.round)、そうでなければそのまま返す
withTax(amount, rate = 0.1) … 税込額(Math.round)を返す。税率は省略可

処理:明細を1行ずつ出力しながら小計を積み上げ、最後に「小計 → 会員割引後 → 消費税込」の順に出力する。

出力仕様(8行):
=== 請求書 ===
ノートPC:128,000円 × 1 = 128,000円
マウス:3,200円 × 2 = 6,400円
USBメモリ:1,500円 × 3 = 4,500円
---
小計:138,900円
会員割引後:125,010円
消費税込:137,511円
期待される結果

出力8行が完全一致

ヒント

関数を3つ先に定義してから処理を書く。ループの中で subtotal(item) を呼んで total に足し込み、ループ後に applyDiscount() → withTax() の順に通す。明細は分割代入 { name, price, qty } で取り出すと読みやすい。

模範解答
const items = [
  { name: "ノートPC", price: 128000, qty: 1 },
  { name: "マウス", price: 3200, qty: 2 },
  { name: "USBメモリ", price: 1500, qty: 3 },
];
const isMember = true;

const subtotal = item => item.price * item.qty;

const applyDiscount = (amount, isMember) =>
  isMember ? Math.round(amount * 0.9) : amount;

const withTax = (amount, rate = 0.1) => Math.round(amount * (1 + rate));

console.log("=== 請求書 ===");

let total = 0;

for (const item of items) {
  const line = subtotal(item);
  total += line;
  const { name, price, qty } = item;
  console.log(`${name}:${price.toLocaleString()}円 × ${qty} = ${line.toLocaleString()}円`);
}

const discounted = applyDiscount(total, isMember);
const taxed = withTax(discounted);

console.log("---");
console.log(`小計:${total.toLocaleString()}円`);
console.log(`会員割引後:${discounted.toLocaleString()}円`);
console.log(`消費税込:${taxed.toLocaleString()}円`);
解説

小さな関数を並べて、処理の流れで組み立てる——これが実務のプログラムの標準的な形。税率が変わっても withTax の中だけ、割引率が変わっても applyDiscount の中だけを直せばよい。変更が1箇所で済む構造を作れることが、関数を学ぶ本当の目的。

また ① の subtotal(item)オブジェクトをまるごと受け取っている点に注目してほしい。subtotal(price, qty) と2つ渡す設計もあり得るが、明細の項目が増えたときに引数が際限なく増える。関連するデータはオブジェクトのまま渡すのが拡張に強い。

次章では map / filter / reduce を学ぶ。ここで書いた for ループが、アロー関数を使って1行に凝縮される。