Page 271 - 你不知道的JavaScript(下卷)
P. 271

};
                   })();

                   foo( 123456 );          // 3810376848.5

               如果你在实现了 TCO 的 ES6 引擎中运行前面的代码,会得到如前显示的 3810376848.5。
               然而,它在非 TCO 引擎里仍然会因 RangeError 而失败。


               7.7.2 非 TCO 优化
               还有几种其他技术可以用来重写代码,使得不需要每次调用时都增长栈。

               其中一种这样的技术叫作 trampolining,它相当于把每个部分结果用一个函数表示,这些
               函数或者返回另外一个部分结果函数,或者返回最终结果。然后就只需要循环直到得到的
               结果不是函数,得到的就是最终结果。

               考虑:

                   "use strict";

                   function trampoline( res ) {
                       while (typeof res == "function") {
                           res = res();
                       }
                       return res;
                   }

                   var foo = (function(){
                       function _foo(acc,x) {
                           if (x <= 1) return acc;
                           return function partial(){
                               return _foo( (x / 2) + acc, x - 1 );
                           };
                       }

                       return function(x) {
                           return trampoline( _foo( 1, x ) );
                       };
                   })();

                   foo( 123456 );          // 3810376848.5

               这个重写需要最小的改动来把递归转化为 trampoline(..) 中的循环。

               (1) 首先,把 return _foo .. 一行封装在 return partial() { .. 函数表达式中。
               (2) 然后,把 _foo(1,x) 调用封装在 trampoline(..) 调用中。
               这个技术不限制调用栈的原因是,每个内部的 partial(..) 函数只是返回到
               trampoline(..) 的 while 循环中,trampolining 运行函数并进行下一次的循环迭代。换句话



               248   |   第 7 章
                                图灵社区会员 avilang(1985945885@qq.com) 专享 尊重版权
   266   267   268   269   270   271   272   273   274   275   276