答え
console.log(Math.max(...[]));
console.log(Math.min(...[]));Math.max() は配列を受け取らないので、... で1つずつに開いて渡します。
→ スプレッド構文と残余
ただし、そのまま使うと3つの穴があります。
穴1: 空の配列で -Infinity になる
const prices = [];
const highest = Math.max(...prices);
console.log(`最高額は ${highest} 円`);引数が1つも無いときの決まりです。エラーにはなりません。
これがそのまま画面に出たり、次の計算に混ざったりします。
console.log(Math.max(...[1, null, 3]));
console.log(Math.max(...[1, undefined, 3]));
console.log(Math.max(...['3', '10']));
console.log(Math.max(...[1, NaN, 3]));console.log(Math.max(...[null, -5]));
console.log(Math.min(...[null, 5]));先に確かめてください。
null を返すか、既定値を返すか、投げるかは仕様しだいです。決めずに -Infinity のまま流さない、というのがここでの要点です。
穴2: 数値でないものが混ざる
try {
[].reduce((a, b) => (a > b ? a : b));
} catch (error) {
console.log(error.name + ': ' + error.message);
}nullは0 として扱われますundefinedとNaNは全体を NaN にします- 文字列は数値に変換されるので、
'3'と'10'は正しく比べられます
undefined と NaN は NaN になるので気づけます。
null だけが静かに通り、答えを変えます。
どちらにも 0 は入っていません。
穴3: 件数が多いと落ちる
... は要素を関数の引数として渡します。
引数を積む場所には限りがあるので、件数が多いと RangeError になります。
実測すると、検証に使っている Node 22.22.3 では
10万件は通り、13万件で Maximum call stack size exceeded になりました。
この境目は処理系と版で変わります。 数を覚えないでください。
件数が読めないときは reduce() を使ってください。
reduce() は初期値を書かないと、空配列で落ちます。
落ちるのは、黙って -Infinity を返すよりましです。 どちらの形でも、空のときにどうするかは自分で決めてください。
最大の「要素」が欲しいとき
値ではなく、その要素そのものが欲しいことのほうが多いはずです。
これではどれが 300 円だったのか分かりません。
1回のループで要素が取れます。
並べ替えても取れますが、要らない仕事が増えます。
toSorted() は元の配列を変えないので、items はそのままです。
sort() を使うと元が並び替わります。
→ 配列を数値の大きさで並び替える
使い分け
| 欲しいもの | 件数が少ない | 件数が多い・不明 |
|---|---|---|
| 最大値 | Math.max(...list) |
list.reduce(...) |
| 最大の要素 | list.reduce(...) |
list.reduce(...) |
| 上位いくつか | toSorted().slice(0, n) |
toSorted().slice(0, n) |
まとめ
- 短いのは
Math.max(...list)。ただし空配列で-Infinity nullは0に化ける。undefinedとNaNは全体をNaNにする- 件数が多いと
RangeError。 境目は環境しだい。読めないならreduce() reduce()は初期値なしだと空配列で落ちる。どちらでも空の扱いは自分で決める- 要素そのものが欲しいなら
reduce()で持ち回る