js原理:尾调用、尾递归

81 浏览发布于 作者 Yang (欢迎转载-请注明出处链接)留下评论分享按钮

一、什么是尾调用

以《你不知道的js》中卷 P316 关于 尾调用尾递归的照片 开篇:

尾调用(Tail Call):指某个函数的最后一步是调用另一个函数( return 一个函数)。

//尾调用:
function f(x){
  return g(x);
}

凡是不是 return 一个函数出去,或者在 return 里加入了其它操作的,都不是尾调用:

以下三种情况,都不属于尾调用:
// 情况一
function f(x){
  let y = g(x);
  return y;
}
// 情况二
function f(x){
  return g(x) + 1;
}
// 情况三
function f(x){
  g(x);
}

//引用:http://es6.ruanyifeng.com/?search=Number%28%29&x=0&y=0#docs/function#尾调用优化


二、什么是尾递归

函数调用自身,称为递归。如果 尾调用自身,就称为尾递归。


三、尾调用会带来什么好处

上面其实已经提到了,会优化内存的使用,特别是在递归时,不会因为递归太深导致调用栈太多,造成溢出。


四、如何使用尾调用的这种优化

当我们在使用递归时,切记一定要写 尾调用 的形式。这样就能让引擎使用 尾调用 优化,ES6 第一次明确规定,所有ECMAScript的实现,都必须部署“尾调用优化”。这就是说,在ES6中,只要我们使用尾递归,引擎就会使用 尾调用优化(调用的过程会被替换为一个循环,可以显著提高速度并避免栈溢出),就不会发生栈溢出,相对节省内存。


五、另外阮一峰的ES6里有提到:ES6的尾调用优化只在严格模式下开启,正常模式是无效的,同时也提到了使用循环改写递归的方式来避免出现调用栈过深(递归转循环,循环转递归,是一种需要重视的编程方式,会有很多应用,我的另一篇文章会专门聊聊这个)。
具体参看: http://es6.ruanyifeng.com/?search=Number%28%29&x=0&y=0#docs/function#尾调用优化

想要打赏,请点击这里

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注