奥が深い関数、詳細は [関数と宣言 · JavaScript Primer \#jsprimer](https://jsprimer.net/basic/function-declaration/) を読んでもらうとして、Lessonでは重要なポイントのみを抑えていきます。
## Reference
- [関数と宣言 · JavaScript Primer \#jsprimer](https://jsprimer.net/basic/function-declaration/)
## Lesson
関数宣言は `function` キーワードを使います。
```js
function funcName(arg1, arg2) {
return arg1 + arg2;
}
```
変数に関数を代入する場合や、一時的に利用する無名関数としては、[[アロー関数 (JavaScript)|アロー関数]]を使うことが多いです。
```js
const funcName = (arg1, arg2) => arg1 + arg2;
```
## Mission 1
#😁EASY
2つの値を引数にとり、大きい値を返す関数を書いてください。
- 引数のバリデーションは不要 (必ず数値型)
- 呼び出し側から必ず2つの引数が渡される前提でOK
- 同じ値の場合はどちらを返してもよい
- `function` キーワードを使うこと
%%
解答例
[[三項演算子 (JavaScript)|三項演算子]]を使うとシンプルに書けます。(まだやってないので使わなくてもOK)
```js
function max(x, y) {
return x > y ? x : y;
}
```
%%
## Mission 2
#😁EASY
Mission 1の関数を[[アロー関数 (JavaScript)|アロー関数]]で書き直してください。
%%
解答例
```js
const max = (x, y) => (x > y ? x : y);
```
%%
## Mission 3
#🙂NORMAL
[[残余引数 (JavaScript)|残余引数]]を使って、可変長の引数を受け取り総和を返却する関数 `sum` を作成し、[[スプレッド構文 (JavaScript)|スプレッド構文]]を使って呼び出すコードを書いてください。
- 引数は必ず1つ以上指定されるという前提でOK
- 引数のバリデーションは不要 (必ず数値型)
```js
// TODO: sumの実装
const nums = [1, 10, 100]
// TODO: numsを使ってsumを呼び出し、console.logで出力
```
%%
解答例
実装は任意の方法でOKです。ループや配列に関するクエストはまだ実施していないため。
```js
// for文ですべてを加算する
function sum(...args) {
let total = 0;
for (const arg of args) {
total += arg;
}
return total;
}
const nums = [1, 10, 100]
console.log(sum(...nums))
```
または
```js
// reduceで畳み込み
const sum = (...args) => args.reduce((ac, x) => ac + x);
const nums = [1, 10, 100]
console.log(sum(...nums))
```
%%
> [!hint]- Hint 1
> [[残余引数 (JavaScript)|残余引数]]は[[配列 (JavaScript)|配列]]データになるので、[[for...of (JavaScript)|for...of]]を使って加算しましょう。
## Mission 4
#😵HARD
Mission 1の関数について、呼び出し側が必ず引数を2つ渡さない場合でも動く関数を書いてください。
- 引数が渡されたら必ず数値型という前提でOK
- 関数名を `max` として以下を満たすこと
```js
max()
// 0 (引数なしは0を返す)
max(1)
// 1 (引数1つはそのまま返す)
max(1, 2)
// 2
max(1, 2, 3)
// 2 (引数3つ目以上は無視でいい)
```
%%
解答例
[[残余引数 (JavaScript)|残余引数]]を使って可変長の引数を表現し、[[分割代入 (JavaScript)|分割代入]]で1つ目と2つ目の引数のみにフォーカスする。未指定の場合は [[undefined (JavaScript)|undefined]] になり、引数が指定された場合は必ず数値型という前提があるのでこれでOK。
```js
// 関数の仮引数に対する分割代入と残余引数を組み合わせる場合
function max(...[x, y]) {
if (x === undefined) {
return 0;
}
// if (!y) { だと max(-1, 0) が -1 になってしまうのでNG
if (y === undefined) {
return x;
}
return x > y ? x : y;
}
```
または
```js
// 残余引数を関数内で分割代入する場合
function max(...args) {
const [x, y] = args;
if (x === undefined) {
return 0;
}
// if (!y) { だと max(-1, 0) が -1 になってしまうのでNG
if (y === undefined) {
return x;
}
return x > y ? x : y;
}
```
または
```js
function max(...args) {
if (args.length === 0) {
return 0;
} else if (args.length === 1) {
return args[0];
} else {
return args[0] > args[1] ? args[0] : args[1];
}
}
```
%%
> [!hint]- Hint 1
> 可変長の引数は[[残余引数 (JavaScript)|残余引数]]で表現すると分かりやすいです。
> [!hint]- Hint 2
> 前提条件があるので、[[undefined (JavaScript)|undefined]]が引数として指定されるケースを考える必要はありません。(引数の数が足りない場合、そこは[[undefined (JavaScript)|undefined]]になりますが)
---
*NEXT* >> [[📗TDQ-009 条件分岐と三項演算子]]