JavaScriptのMath.sumのおはなし

2022-01-18

経緯

元ネタ

「JavaScriptのMathオブジェクトのsumメソッドについて現役エンジニアが解説」というタイトルの記事が出てきて、最近だと Math.sum() 実装されてるんか。へー。って思って読んだら「Math.sum() はないので自分で実装しましょう」という内容でプログラミングスクール滅べと思った。

徳丸さんの引用ツイート

これ、検索して読みましたが、任意個数の引数を合計するメソッドと思いきや、単にa+bを返すメソッドだったので、「恥を知れ」と思いました

私の引用ツイート

JavaScript、Array.prototype.reduceがあるから、

nums.reduce((x, y) => x + y)

でええんちゃうの…?

元ネタと思われるコード

多分、これ。

JavaScriptのMathオブジェクトのsumメソッドについて現役エンジニアが解説【初心者向け】

var sum = function (a, b) {
 return a + b;
};

console.log(sum(1, 2));

現役ハッカー(略)が解説

そのコードは

1 + 2

と等価なので、完全にフールである。

JavaScriptにはMath.sum()は存在しない。 だが、そもそもそのようなものは必要ないし、そもそもsum関数があるとして、一般的にはイテレータ操作だから、MathよりはArrayEnumeratorに属するべきものだ。

私が言及した

nums.reduce((x, y) => x + y)

は有効なコードであであり、関数の自作などせずとも目的を達成できる。

Array.prototype.reduce()はRubyで言うところのEnumberable#injectのようなものである。 コールバック関数を受け取り、Array.prototype.forEachのようなイテレータ操作メソッドが追加された過程で追加されたものである。 Mozilla Firefox 3からサポートされた。

コールバック関数は2つの引数を取り、(最後の戻り値, 次の値)である。 [1, 2, 3].reduce()だとしたら、まずひとつ目の値である1はコールバックの評価をされず戻り値という扱いになる。 そして、1回目のコールバック関数は(1, 2)という引数で起動される。 2回目のコールバック関数のひとつ目の引数は、この1回目のコールバック関数の戻り値となり、2つ目の引数は3となる。

() =>という書き方は、最近の関数の書き方だ。 まず、(arg) => {code}というアロー関数という形式がある。

引数がひとつである場合、カッコは省略でき、arg => {code}と書くことができる。

さらに新しい書き方としてcodeを囲むブレースを省略できる。 これは単一の式文からなる場合に省略でき、省略した場合returnが自動的に行われる。 そのため、

(x, y) => x + y

(x, y) => { return x + y }

と等価である。

これらを組み合わせて、

nums.reduce((x, y) => x + y)

が適切な答えとなる。

なお、この形式のアロー関数がサポートされたのはかなり最近(Firefox 52/Chrome 58)なので、ブラウザ互換性を重視するならば、

nums.reduce(function(x, y) { return x + y})

となる。