ECMAScript 6thには仕様として末尾呼び出しの最適化が盛り込まれている(ECMAScript 2015 Language Specification14章の6)。そしてES 6thのコードをES 5thに変換するbabelは末尾再帰呼び出しの最適化を実装しているらしい。試してみた。
再帰といえば定番のフィボナッチ数の計算を末尾再帰で書いてみる。
function fib(n, a=0, b=1) { if (n < 1) { return a; } return fib(n-1, b, a+b); }
このES 6thなコードをbabelでES 5thにトランスパイルしてみると…
"use strict"; function fib(_x3) { var _arguments = arguments; var _again = true; _function: while (_again) { var n = _x3; a = b = undefined; var a = _arguments[1] === undefined ? 0 : _arguments[1]; _again = false; var b = _arguments[2] === undefined ? 1 : _arguments[2]; if (n < 1) { return a; } _arguments = [_x3 = n - 1, b, a + b]; _again = true; continue _function; } }
すごい、whileループになってます!!ラベル付きループ!!存在忘れていた。
ちょいといたずらして末尾呼び出しではなくして
function fib(n, a=0, b=1) { if (n < 1) { return a; } return 0 + fib(n-1, b, a+b); }
トランスパイルしてみると…
"use strict"; function fib(n) { var a = arguments[1] === undefined ? 0 : arguments[1]; var b = arguments[2] === undefined ? 1 : arguments[2]; if (n < 1) { return a; } return 0 + fib(n - 1, b, a + b); }
今度は再帰呼び出しのままに変わらず。