深入前端尾递归
创始人
2024-05-26 06:46:23
0

在深入探讨前端尾递归前,我们先来了解递归和尾调用两个概念

递归

在函数内部调用自身,一般来说递归有两个状态

  • 递归状态(继续递归)
  • 最终状态(终止递归)

递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。绝大多数编程语言支持函数的自调用,在这些语言中函数可以通过调用自身来进行递归。计算理论可以证明递归的作用可以完全取代循环,因此在很多函数编程语言(如Scheme)中习惯用递归来实现循环。(递归算法)

在这里插入图片描述
一般而言,递归使函数看起来更加简洁,但相对循环来说不易理解。
在JavaScript语言中,函数中调用函数会形成调用栈(call stack),栈是一后进先出的结构,当函数调用链足够长时,会发生栈溢出,程序会报错,因此在使用递归时,要注意溢出的情况。

递归循环
程序简洁易阅读
栈溢出不会发生溢出

尾调用

在讨论尾调用前,我们先强调一点,尾调用的局限场景

  • safari浏览器实现了对尾调用的支持
  • 严格模式下生效

含义
函数最后一步是调用一个函数,最后一步并不指最后一行。可简单归纳为return + fn()

function bar(){}
function foo1() {bar()
}
// foo1不是尾调用,实际等价于
function foo1() {bar()return undefined
}// foo2不是未调用,因为最后一步不是调用一个函数,而是 bar() + 1 求和
function foo2() {return bar() + 1
}// 是尾调用
function foo3(num) {switch(num) {case 1:return bar()case 2: return bar()}
}

尾调用由于最后一步是调用一个函数,所以外部函数的调用位置,内部变量不需要用到,因此不要保存外部函数的调用帧,因此执行到尾调用函数的最后一步时,内存函数的调用帧取代最外层函数的调用帧。不会发生调用栈溢出。

尾递归

尾递归,递归结合尾调用,或者说尾调用的函数是自身。

尾递归优化

前提条件

  • 严格模式
  • Safari浏览器

尾递归溢出

function sum(x, y) {if (y > 0) {return sum(x + 1, y - 1);} else {return x;}
}sum(1, 100000);

在这里插入图片描述

尾调用优化

蹦床函数

封装一个蹦床函数解决调用栈溢出

   function trampoline(f) {while(typeof f == 'function') {f = f()}return f}

trampoline函数接收一个函数,将递归改造成循环,我们将sum函数进行改造,返回sum函数的一个副本。

function sum(x, y) {if (y > 0) {return sum.bind(null,x + 1, y - 1);   // 这里可以不使用bind,直接返回一个函数,函数内部调用sum方法} else {return x;}
}
// 不使用bindtrampoline(sum(1, 100000))   // 100001

为了解决调用栈溢出的问题,我们封装了一个trampoline函数,另外对sum函数进行了改造。

tco函数

 function tco(f) {let value,actived = false,accumulated = [];return function () {accumulated.push(arguments);if (!actived) {actived = true;while (accumulated.length > 0) {value = f.apply(null, accumulated.shift());}actived = false;return value;}};}var sum = tco(function (x, y) {if (y > 0) {return sum(x + 1, y - 1);} else {return x;}});

巧妙利用accumulated,循环不会终止。每次执行到apply时,accumulated中会push进下一次参数,继续while循环。tco函数也使用了闭包。

总结

本文主要讨论了以下几个问题
1)前端中的尾递归,介绍了递归,尾调用,和尾递归三个基本概念。
2) 说明了尾调用的优化需要在严格模式下才会生效,尾调用优化在safari浏览器中得到实现。
3)递归可能造成调用栈溢出
4)可以使用循环解决调用栈溢出问题
5)封装了trampoline函数和tco函数,这两个函数中巧妙利用循环解决了调用栈溢出的问题。

参考:尾递归优化的实现

相关内容

热门资讯

虞书欣谈成名的代价令人心疼,如... 虞书欣谈成名的代价令人心疼,如今她在圈内的前景如何?虞书欣在圈内前景是很不错的,大家都很喜欢她,也有...
最有效的减肥食谱 最有效的减肥食谱谁有最有效的减肥食谱呢?麻烦给一个吧?急求最有效的减肥食谱,听说有一个什么汤的可以很...
关晓彤鹿晗被曝月底会分手,你对... 关晓彤鹿晗被曝月底会分手,你对于他们两个的爱情有什么看法?当初我也觉得他们俩的感情肯定不会长久的,但...
她曾在家中喂猪,却被张艺谋相中... 她曾在家中喂猪,却被张艺谋相中一夜成名,魏敏芝如今过得怎样?魏敏芝过得非常不错啊,而且当地的头衔也是...
电影《中邪》主要讲了什么? 电影《中邪》主要讲了什么?中邪的剧情简介 · · · · · ·大学生丁鑫和刘梦为拍摄农村风俗纪录片...
可以在营业厅查到短信的内容吗? 可以在营业厅查到短信的内容吗?查自己的短信==如果你是本人应该可以…不是本人是不可以的那是别人的隐私...
春日时雨时晴,杏花开时,小雨落... 春日时雨时晴,杏花开时,小雨落在身上,衣服欲湿未湿;杨柳风最柔,吹到脸上也下觉其寒。是什么诗句沾衣欲...
低学历的女人真的不能娶吗? 低学历的女人真的不能娶吗?我觉得不是的,娶妻子还是主要看对方的品性如何,而不是在意对方的学历。不一定...
电影配音问题 懂的进来 不是很... 电影配音问题 懂的进来 不是很难我想知道一个问题 比如说 一个电影 演员是 X 那他的说...可以是...
关于大蒜的谜语有哪些 关于大蒜的谜语有哪些有关蒜的谜语有:两二小,头长草 (打字一)谜底:蒜弟兄七八个,围着柱子坐,只要一...
怎么夸老师漂亮 怎么夸老师漂亮老师您长得太有气质了,非常出众,我身为一个女孩子都快要把持不住了。就直接一点说:老师你...
一般怎么钢琴即兴伴奏,一拿到简... 一般怎么钢琴即兴伴奏,一拿到简谱就能伴奏的和弦 天空之城简易般的可一参考 摸摸就出来的 弹一个音 ...
我对异地女友说,异地太苦了我真... 我对异地女友说,异地太苦了我真心问你,你和我一起内心快乐吗?她说,不管日子再苦,有你就是甜的?你一个...
为什么叫镇江 为什么叫镇江为什么叫镇江意义为"Garrison of the Yangtze River"
在足球历史上,阿贾克斯都获得过... 在足球历史上,阿贾克斯都获得过多少次欧冠?一共应该是获得过4次冠军,而且他真的是特别厉害,很少有人可...
时间简史是谁写的? 时间简史是谁写的?史蒂芬·威廉·霍金
我爱她,但她爱他。 我爱她,但她爱他。如果换了我是你!我会一直的爱着她!她爱着他,你又爱着他!她知道爱一个不爱自己人的资...
歌词:我是你的月亮,是你夜里的... 歌词:我是你的月亮,是你夜里的光芒。叫月光曲,嘿嘿
枪神纪里面的英文歌曲叫什么? 枪神纪里面的英文歌曲叫什么?枪神纪里面的英文歌曲叫什么?一首是男的一首是女的,女的那首好像有一句是,...
中外小朋友 大家手拉手 来自五... 中外小朋友 大家手拉手 来自五大洲 是什么歌名?中外小朋友 大家手拉手 来自五大洲 是什么歌名?《庆...