6.関数
学習目標
- 処理を関数にまとめて定義し、呼び出せる
- 引数で値を受け取り、戻り値で結果を返す関数を書ける
配列とループ: 最大値の探索で、配列から最大値を求めるプログラムを書きました。別の配列に対しても同じ処理をしたい場合、次のように同じコードを書き足すことになります。
// 1つ目の配列から最大値を求めるconst numbers = [34, 72, 15, 88, 43];let max1 = numbers[0];
for (let i = 1; i < numbers.length; i++) { if (numbers[i] > max1) { max1 = numbers[i]; }}
console.log(max1);
// 2つ目の配列から最大値を求めるconst scores = [80, 65, 90, 70, 85];let max2 = scores[0];
for (let i = 1; i < scores.length; i++) { if (scores[i] > max2) { max2 = scores[i]; }}
console.log(max2);8890同じコードが2回並んでいます。配列の数が3つ、4つと増えれば、その分だけ同じコードを書く必要があります。こうした重複をなくすために、処理に名前をつけて1か所にまとめ、何度でも実行できる仕組みを 関数 と呼びます。
2. 関数の定義と呼び出し
Section titled “2. 関数の定義と呼び出し”2-1. 基本の書き方
Section titled “2-1. 基本の書き方”function キーワードを使って、処理に名前をつけて関数として定義します。
function 関数名() { 実行する処理}function greet() { console.log("こんにちは");}
greet();greet();こんにちはこんにちはfunction greet() { ... } で、console.log("こんにちは") という処理に greet という名前をつけて関数として定義します。
greet() と書くと、定義した処理が実行されます。これを 関数の呼び出し と言います。greet() を2回書いているので、こんにちは が2回出力されます。
2-2. 関数の実行順序
Section titled “2-2. 関数の実行順序”次のコードで、関数を含むプログラムの実行順序を確認します。
console.log("1: 開始");
function greet() { console.log("2: 関数の中");}
console.log("3: 呼び出し前");greet();console.log("4: 呼び出し後");1: 開始3: 呼び出し前2: 関数の中4: 呼び出し後実行の流れを追います。
console.log("1: 開始")が実行され、1: 開始が出力されるfunction greet() { ... }は関数の定義なので、greet関数の中は実行されないconsole.log("3: 呼び出し前")が実行され、3: 呼び出し前が出力されるgreet()で関数が呼び出され、greet関数の中のconsole.log("2: 関数の中")が実行されて2: 関数の中が出力される- 関数の処理が終わると、
greet()の次の行に戻り、console.log("4: 呼び出し後")が実行されて4: 呼び出し後が出力される
3-1. 引数の基本
Section titled “3-1. 引数の基本”先ほどの greet 関数は毎回同じ挨拶しかできません。相手の名前に応じてメッセージを変えたい場合はどうすればよいでしょうか。
関数定義の () の中に 引数 と呼ばれる変数を書いておくと、関数を呼び出すときにその変数へ値を渡せます。
function 関数名(引数) { 実行する処理}function greet(name) { console.log(name + "さん、こんにちは");}
greet("田中");greet("鈴木");田中さん、こんにちは鈴木さん、こんにちはfunction greet(name) の name が引数です。greet("田中") を呼び出したときの流れを追います。
"田中"が引数nameに渡される- 関数の中の
name + "さん、こんにちは"が評価され、"田中さん、こんにちは"となる 田中さん、こんにちはが出力される
greet("鈴木") の場合も同じ仕組みで、鈴木さん、こんにちは が出力されます。
3-2. 複数の引数
Section titled “3-2. 複数の引数”引数はカンマで区切って複数書くことができます。
function add(a, b) { console.log(a + b);}
add(10, 20);add(3, 7);3010複数の引数があるとき、呼び出し時の値は書いた順番に対応します。add(10, 20) を呼び出したときの流れを追います。
- 値が引数に渡される
- 1 番目の
10→ 1 番目の引数a - 2 番目の
20→ 2 番目の引数b
- 1 番目の
a + bが評価され、30となる30が出力される
add(3, 7) の場合も同じ仕組みで、3 + 7 が評価されて 10 が出力されます。
4. 戻り値
Section titled “4. 戻り値”4-1. 戻り値の基本
Section titled “4-1. 戻り値の基本”関数の結果を変数に保存したり別の式で使ったりしたい場合は、関数の中から呼び出し元へ値を返します。返される値を 戻り値 と呼び、return で指定します。
function 関数名(引数) { return 値;}function add(a, b) { return a + b;}
const result = add(10, 20);console.log(result);console.log(add(3, 7));3010add(10, 20) を呼び出したときの流れを追います。
add(10, 20)が評価され、戻り値の30になる30がresultに代入されるconsole.log(result)で30が出力される
console.log(add(3, 7)) のように、変数を経由せず console.log の引数として直接渡すこともできます。
4-2. return の有無
Section titled “4-2. return の有無”関数に return があるかないかで、呼び出し元が結果を受け取れるかが決まります。同じ足し算を行う関数を return ありとなしで比べてみます。
function add(a, b) { console.log(a + b);}
const x = add(10, 20);console.log(x);30undefined関数の中の console.log(a + b) が 30 を出力します。add には return がないので戻り値は undefined で、console.log(x) は undefined を出力します。
function add(a, b) { return a + b;}
const y = add(10, 20);console.log(y);30add は return a + b で 30 を返します。y に 30 が入り、console.log(y) で 30 が出力されます。
関数の結果を呼び出し元で使いたい場合は return を書きます。
4-3. 戻り値を使った計算
Section titled “4-3. 戻り値を使った計算”戻り値を変数に保存すれば、別の計算に活用できます。次のプログラムは、関数で小計を計算し、そこから税込みの合計を求めます。
function calcSubtotal(price, quantity) { return price * quantity;}
const subtotal = calcSubtotal(500, 3);const tax = subtotal * 0.1;const total = subtotal + tax;console.log(total);1650subtotal には 1500 が入ります。その subtotal が tax と total の 2 つの計算で使われ、最終的に 1650 が出力されます。
return で値を返すことで、結果を subtotal に保存し、tax や total の計算に使えます。
4-4. 早期リターン
Section titled “4-4. 早期リターン”関数の中には return を複数書くことができます。return が実行されると関数はそこで終わるので、最初に実行された return だけが動き、残りは実行されません。この書き方を 早期リターン と呼びます。
function checkAge(age) { if (age < 0) { return "不正な値です"; } if (age >= 18) { return "成人です"; } return "未成年です";}
console.log(checkAge(20));console.log(checkAge(-1));console.log(checkAge(15));成人です不正な値です未成年ですそれぞれの呼び出しでどの return が実行されるかを追います。
checkAge(20):age < 0はfalseなので 1 つ目のifを通過します。age >= 18がtrueなのでreturn "成人です"で関数が終了します。3 つ目のreturnには到達しません。checkAge(-1):age < 0がtrueなので、すぐにreturn "不正な値です"で関数が終了します。残りの 2 つのreturnは実行されません。checkAge(15):age < 0もage >= 18もfalseなので、2 つのifを通過してreturn "未成年です"が実行されます。
5. 処理の関数化
Section titled “5. 処理の関数化”5-1. 大きいほうを返す関数
Section titled “5-1. 大きいほうを返す関数”条件分岐: 最大値の判定で、2 つの数から大きいほうを求めるコードを書きました。同じロジックを関数にまとめると、どんな 2 つの値でも使い回せます。
function getMax(a, b) { let max; if (a > b) { max = a; } else { max = b; } return max;}
console.log(getMax(30, 45));console.log(getMax(100, 50));function getMax(a, b) { if (a > b) { return a; } return b;}
console.log(getMax(30, 45));console.log(getMax(100, 50));45100どちらの書き方でも、getMax(30, 45) では 45 が、getMax(100, 50) では 100 が返されます。「let max を使う」形は 条件分岐: 最大値の判定 の構造を関数に包んだもので、「早期リターンを使う」形は 早期リターン のパターンを応用したものです。
5-2. 配列から最大値を返す関数
Section titled “5-2. 配列から最大値を返す関数”配列から最大値を求める処理を関数にまとめます。
function findMax(arr) { let max = arr[0];
for (let i = 1; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; } }
return max;}
console.log(findMax([34, 72, 15, 88, 43]));console.log(findMax([80, 65, 90, 70, 85]));8890どんな配列を渡しても最大値が返ってきます。処理は1箇所にまとまっているので、ロジックを修正したいときも findMax の中だけを直せば、すべての呼び出し箇所に反映されます。
5-3. 配列の合計を返す関数
Section titled “5-3. 配列の合計を返す関数”配列とループ: 合計値の計算で書いた配列の合計を求めるコードを、関数にまとめます。
function calcSum(arr) { let sum = 0;
for (let i = 0; i < arr.length; i++) { sum = sum + arr[i]; }
return sum;}
const scores = [80, 65, 90, 70, 85];const total = calcSum(scores);const average = total / scores.length;console.log(total);console.log(average);39078calcSum(scores) の戻り値 390 が total に代入され、total / scores.length で平均 78 が計算されます。