関数・引数・戻り値
指導者向けの公開補足
学習本文に加えて、指導の視点・背景・授業での確かめ方を示します。どなたでも読めます。
指導の焦点
引数を渡すことと、戻り値を受け取ることを分けて追う。画面へ表示するだけの処理と、値を返す処理は同じではない。
一歩踏み込んだ背景
関数へ分けると読みやすくなる可能性がある一方、外側の変数への依存が多いと再利用やテストが難しくなる。入出力が見える設計を優先する。
授業での確かめ方
同じ関数に複数の引数を渡し、呼び出し側から戻り値を使う。表示だけで済ませた場合に後の計算へつなげられるか、比較させる。
制度・規格等は本文末尾の参考資料も確認してください。
JSFiddleでコードを試す
JSFiddleは、ブラウザーでHTML・CSS・JavaScriptを入力して実行できるサービスです。短い動作確認から始められます。
- 新しい編集画面を開きます。JavaScriptは通常のJavaScriptを選び、外部ライブラリは追加しません。
- HTML欄にはページの本文、CSS欄には見た目、JavaScript欄には処理を書きます。HTML欄に
<html>や<body>は不要です。JavaScript欄に<script>は付けません。 - DOMを使う例では、JavaScriptの実行タイミングを「On Load」「On DOM Ready」または「No wrap - bottom of body」にします。
- 「Run」を押してResult欄を確認します。書き換えたら再びRunを押します。
console.logの結果は通常、ページではなく開発者ツールのコンソールに出ます。このサイトの計算例をResult欄で読みたいときは、HTML欄に次を入れます。
<pre id="output"></pre>JavaScript欄には次を入れ、console.log(2 + 3);の行を、試したいコード一つに置き換えます。独立した例を複数まとめて貼らないでください。
{
const output = document.getElementById("output");
const console = {
log(...values) {
output.textContent += values.join(" ") + "\n";
}
};
console.log(2 + 3);
}Runを押すと「5」と表示されます。外側の波括弧の中だけで表示用のconsoleを用意しているため、ブラウザー本来のコンソールは変更しません。
HTMLとJavaScriptの両方を載せた実習例は、この表示用コードで囲まず、それぞれの欄へ分けて貼り付けます。保存・共有時は公開範囲を確認し、個人情報やパスワードを入力しないでください。コードは手元にも残しましょう。
この単元でできるようになること
Section titled “この単元でできるようになること”- 引数、仮引数、戻り値を実行の流れに対応させられる。
- 外側の変数へ依存しない小さな関数を設計できる。
- 通常値と境界値で、関数の約束を検証できる。
処理をまとめる単位
Section titled “処理をまとめる単位”関数は、ひとまとまりの処理に名前などを付け、必要な場所から呼び出せるようにする仕組みである。似たコードをまとめれば、計算方法を変える箇所を減らせる。ただし、単に長いコードを一か所へ押し込むだけでは読みやすくならない。「何を受け取り、何を返すか」を説明できる単位に分けたい。
架空の工作講座で、材料の束数を求めよう。一束に四枚入り、必要枚数を満たす最小の束数を返す関数を作る。必要枚数は零以上の整数とする。零枚なら零束であり、余分に一束を加える規則はない。
function bundlesFor(sheets) { return Math.ceil(sheets / 4);}console.log(bundlesFor(0), bundlesFor(4), bundlesFor(5));出力は 0 1 2。定義の sheets は受け取った値を扱う仮引数で、呼び出し時に渡す0、4、5が引数である。return は計算結果を呼び出し元へ返し、その関数の実行を終える。関数を定義しただけでは、呼び出しの処理は実行されない。
表示と戻り値は別のもの
Section titled “表示と戻り値は別のもの”console.log は値を表示する操作であり、呼び出し元が計算に使う値を返す return と同じではない。束数を画面へ表示するだけの関数では、その結果を料金計算へつなげにくい。まず値を返す関数を作り、表示する場所は呼び出し側で決めると、使い道を変えやすい。
function bundlesFor(sheets) { return Math.ceil(sheets / 4);}function materialCost(sheets, pricePerBundle) { return bundlesFor(sheets) * pricePerBundle;}console.log(materialCost(9, 180));出力は 540。九枚には三束必要で、一束百八十円を掛ける。materialCost は束数の求め方を自分の中へ複製せず、既存の関数を呼び出す。束の入り数を変えるなら、どの関数の約束を変える必要があるかを検討する。
| 呼び出し | 受け取るもの | 返すもの |
|---|---|---|
| 束数の計算 | 必要な枚数 | 最小の束数 |
| 材料費の計算 | 必要な枚数と一束の価格 | 合計金額 |
| 表示 | 表示したい値 | この教材では戻り値を利用しない |
約束を明確にする
Section titled “約束を明確にする”この関数は、負の値や文字列を受け取ったときの処理を含めていない。利用側が零以上の整数を渡すという前提である。実際に外部から入力を受ける場面では、呼び出す前に確認するか、関数自身が不正な入力を拒否する仕様にする。
「どんな入力でもそれらしい結果を返す」より、「受け付ける値と受け付けない値を明確にする」方が不具合を発見しやすい。束の価格が税込みなのか、端数処理が必要なのかといった条件も、関数名だけでは分からないなら仕様に記録する。
境界のテストでは、零、一、四、五枚を用意する。ちょうど一束の枚数と、その一枚先を試すことで、切り上げを忘れていないかを確認できる。期待値は関数の式をコピーせず、束に実際に入る枚数から考えるとよい。
スコープと副作用
Section titled “スコープと副作用”関数内で宣言した変数は、その関数の処理のために使う。外側の同名変数を変更しない設計なら、呼び出し順に結果が左右されにくい。次の例では、total は関数内の合計で、外側の total とは別の名前の範囲にある。
const total = 99;function sumValues(values) { let total = 0; for (const value of values) { total = total + value; } return total;}console.log(sumValues([2, 5]), sumValues([]), total);出力は 7 0 99。同じ入力を渡せば同じ合計を返し、元の配列も外側の合計も変えない。このような小さな関数は、他の処理の状態を再現しなくてもテストしやすい。外部の状態を変更したり画面に出力したりすることは副作用と呼ばれ、必要な場合もあるが、どこで起こるかを明確にしたい。
関数へ配列を渡すと、その中身を変更できることがある。「関数の中の処理だから外には影響しない」とは限らない。引数を変更する関数なのか、新しい値を返すだけなのかも、利用者にとって重要な約束となる。
注意: 関数を細かくすれば必ず良くなるわけではない。名前を読んでも役割が分からない分割や、引数が過剰に多い設計は理解を難しくする。一つの関数が担う目的と、必要な入力の関係を優先しよう。
| 用語 | 意味 |
|---|---|
| 関数 | 呼び出して利用できる処理のまとまり |
| 引数 | 呼び出し時に渡す値 |
| 仮引数 | 渡された値を関数内で扱うための名前 |
| 戻り値 | 関数から呼び出し元へ返す値 |
| 副作用 | 戻り値以外に外部の状態などへ与える変化 |
- 必要枚数が八枚と九枚のとき、最初の関数の戻り値をそれぞれ求めよう。
- 束数を表示するだけで戻り値を返さない関数にすると、料金計算で困る理由を説明しよう。
- 合計の例で空配列を渡したとき、零を返せる理由と、外側の99が変わらない理由を説明しよう。
問1の解答例を見る
八枚なら2、九枚なら3。四枚一束なので、枚数を4で割った値を切り上げた束数を返す。
問2の解答例を見る
画面へ表示するだけでは、呼び出し元が計算に使う戻り値を受け取れない。JavaScriptではreturnがなければundefinedとなり、その値を掛け算しても正しい料金を求められない。
問3の解答例を見る
関数内のtotalを0で初期化し、空配列では反復しないまま0を返すためである。関数内の局所変数totalと、外側のtotalは別なので、外側の99は変わらない。