おー、この回答はちょっと思いつきませんでした。
素敵ですね…覚えておいて今度どっかで使おう。
JavaScript
1function add(n){
2 var fn = function(x) {
3 return add(n + x);
4 };
5
6 fn.valueOf = function() {
7 return n;
8 };
9
10 return fn;
11}
12
13console.log(
14 Array(100000)
15 .fill(0)
16 .map((_, i) => i + 1)
17 .reduce((sum, it) => sum(it), add)
18 .valueOf()
19)
20// 5000050000
そして使い方はこうですか。
はい、大体理解したので早速解説に移ります。
addは関数です。
中身でfnという関数を宣言して、fn.valueOfというプロパティをくっつけてすぐに返します。
2回目以降が素晴らしくて、
2回はfnに代入された引数がxの無名関数が実行されます。
その結果はreturn add(n + x)
足し算した結果が再帰関数のようにaddに転がり込み、
fnを作成、valueOfプロパティをくっつけて帰ってきます。
3回目以降は全て2回目と同様です。
何回呼び出しても今作ったfnが帰ってきます。
でもこいつ関数じゃん、合計結果の数値が欲しいんだけど?
最終的に値を取り出す時の事を想定してvalueOfが用意されているようです。
値を取り出す時はプロパティのvalueOfを使って取り出しましょう。
JavaScript
1console.log(add(1)(2)(5));
2// function
3console.log(add(1)(2)(5).valueOf());
4// 8
おまけ: valueOfプロパティの効果
命題がadd(1)(2)(3)
…と無限にチェーン出来るという事は、関数を返し続ける関数である必要があります。
じゃあ値を取り出したくなってもよくわかんないよね…
今回の模範解答はたまたまvalueOfが宣言されていたのだけど……
JavaScriptにはインスタンス化されたオブジェクト等、
Stringとして表せられないものには大抵valueOf
というメソッドが用意されており
何時でも値に変換出来るようにするというルールがあります。
JavaScript
1function add(n){
2 var fn = function(x) {
3 return add(n + x);
4 };
5
6 fn.valueOf = function() {
7 return n;
8 };
9
10 return fn;
11}
12
13// console.logしたらf 6が表示されるけどなんだ?
14console.log(add(1)(2)(3)) // f 6
15
16// 足し算すると普通にNumber型っぽく計算に使える!?
17console.log(10 + add(1)(2)(3)) // 16
18
19// valueOfがあればなんでもいけんの?じゃあこれは?
20console.log(10 + {
21 name: 'taro',
22 age: 17,
23 valueOf: function(){ return this.age }
24})
25// 27
26
27// 配列とかどうすんだ?
28var arr = [1, 2, 3];
29arr.valueOf = function(){
30 var sum = 0
31 for (var i = 0; i < this.length; i++) {
32 sum += this[i]
33 }
34 return sum
35}
36console.log(10 + arr) // 16
こういう効果があります。
この辺も含めると、質問文のコードは模範解答となるのは間違いないでしょう。
ただ、add(1)(2)
の結果が3という元ネタサイトの記述は違和感がありますけどね。
まぁconsole.logを使って「f 3」と表示されるのはChromeの機能であり
Node.jsや別のブラウザでconsole.logに放り込めばそのまま3と表示される可能性はあります。
(Node.jsでは{ [Function: fn] valueOf: [Function] }
と表示されて全然駄目ですが)
問題の関数を返し続ける関数の時点でかなりイレギュラーな問題でしたね。
でも頭の体操としては楽しい問題だと思いますし、コードに深みが出る良い問題&模範解答だと思います。