美文网首页
尾调用优化

尾调用优化

作者: LUGY | 来源:发表于2018-01-23 11:26 被阅读0次

所谓尾调用,就是指某个函数的最后一步是调用另一个函数。 这里有一个隐含要求,就是最后一步只能是单纯的函数调用,不能有其他操作。

function f(x){

  return g(x);

}  // 这是尾调用

function f(x){

  return g(x) + 1;

} // 这不是尾调用, 因为最后一步是一个带有函数调用的表达式 

在代码中使用尾调用的写法有什么好处呢,尾调用优化到底能优化什么呢,答案是内存。

函数调用会在内存形成一个"调用记录",又称"调用帧"(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用记录上方,还会形成一个B的调用记录。等到B运行结束,将结果返回到A,B的调用记录才会消失。如果函数B内部还调用函数C,那就还有一个C的调用记录栈,以此类推。所有的调用记录,就形成一个调用栈(call stack)。

尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。这就是"尾调用优化"的意义。

尾调用的写法很适合用来实现递归,一个函数在尾部调用自身,就形成尾递归。写过递归的人都知道,递归如果控制不好,很容易出现栈溢出,而尾递归由于上述特性,可以完美地规避这个问题(尾递归永远只有一个调用帧,不会出现栈溢出)。

function factorial(n, total) {

  if (n === 1) return total;

  return factorial(n - 1, n * total);

} // 一个尾递归的例子, 阶乘函数

JS的尾递归优化必须在严格模式下才能够生效(ES6标准)。

在JS文件的顶层加上"use strict",进入严格模式。 在严格模式种,无法使用函数内置的两个变量,arguments 和 func.caller。

arguments 返回函数收到的所有参数,  func.caller返回函数的调用者, 实际上,这两个内置变量都记录了函数的调用帧,所以,在普通模式下,即使使用了尾调用写法,也无法保证调用帧唯一,在严格模式下,这两个变量被禁用,因此可以保证只有一个调用帧。

从ES6开始, 所有 ECMAScript 的实现,都必须部署"尾调用优化",即都要使用严格模式。

相关文章

  • 什么是尾调用?什么是尾递归?尾调用的优化?尾递归优化?

    尾调用优化 尾递归(尾调用优化)

  • 尾调用 & 尾递归 & 尾调用优化

    参考 递归和栈帧的调用原理[https://blog.csdn.net/poiuyds/article/detai...

  • 尾递归优化

    “尾递归优化”的含义是:如果递归函数属于尾递归,那么运行时会优化其调用过程。优化主要针对调用栈,将多层调用,转化为...

  • 尾调用优化

    所谓尾调用,就是指某个函数的最后一步是调用另一个函数。 这里有一个隐含要求,就是最后一步只能是单纯的函数调用,不能...

  • 尾调用优化

    什么是尾调用 尾调用(Tail Call)是函数式编程的一个重要概念,就是指某个函数的最后一步是调用另一个函数。 ...

  • 尾调用优化

    尾调用优化 尾递归 正常递归 尾递归 改写以上代码,使其只有一个参数: 总结一下,递归本质上是一种循环操作。纯粹的...

  • 尾调用优化

    什么是尾调用优化? 尾调用优化是指你可以避免重新分配给一个函数新的堆栈因为正在调用的函数会简单的返回它从已经调用过...

  • 尾调用优化

    1.尾调用是什么 尾调用指某个函数的最后一步是调用另一个函数。 错误例子: 1.递归优化 例: 说明:同样是阶乘,...

  • 尾调用优化

    Tail Call Optimization 出现在另一个函数“结尾”的函数调用。这个调用结束后就没有其他事情要做...

  • 尾调用,尾递归优化

    函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在...

网友评论

      本文标题:尾调用优化

      本文链接:https://www.haomeiwen.com/subject/ftqsaxtx.html