深入前端尾递归
创始人
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函数,这两个函数中巧妙利用循环解决了调用栈溢出的问题。

参考:尾递归优化的实现

相关内容

热门资讯

南宁警方通报“某学校发生一起伤... 16日晚,南宁市公安局江南分局官方微博发布警情通报,全文如下:
钱文海出任国都证券董事长!浙商... 国都证券5月16日公告,其于前一日召开2025年第一次临时股东会,并选举产生了新一届董事会、监事会。...
成都拟对“砸车侠”等见义勇为人... 中新网成都5月16日电 从不顾自身安危跳河砸车的“砸车侠”,到合力勇斗持刀歹徒的普通邻里,见义勇为人...
中原内配:5月16日召开董事会... 中原内配(维权)(SZ 002448,收盘价:8.25元)5月16日晚间发布公告称,公司第十一届第一...
集装箱出厂,方向美国!“中国电... 转自:交汇点编者按:当前,单边主义、保护主义加剧,外部环境不确定不稳定因素增多,面对困难和挑战,我国...
首批商用堆产碳-14同位素投入... 中证报中证网讯(记者杨洁)5月16日,记者自中国核电获悉,当日,首批商用堆产碳-14同位素产品从中国...
财联社5月16日晚间新闻精选 转自:财联社【财联社5月16日晚间新闻精选】 1、证监会鼓励私募基金参与上市公司并购重组,首次建立简...
中兰环保:实控人孔熊君拟减持不... 中兰环保(300854.SZ)公告称,公司实际控制人孔熊君计划减持不超过3,031,305股,占公司...
宁德时代上市“倒计时”:厘定每... 宁德时代将5月20日在联交所主板开始买卖,每股263.00港元,筹资规模扩大至46亿美元,月度期权将...
上海首创首发进口消费品检验便利... 5月16日,上海市商务委员会与上海海关联合发布《关于开展首发进口消费品检验便利化措施试点的公告》,在...
全球粮食危机报告:去年逾2.9... 中新社北京5月16日电 (记者 刘亮)16日发布的《全球粮食危机报告》显示,2024年,53个国家和...
京东618于5月底开启 将为用... 中国青年报客户端讯(中青报·中青网见习记者 刘佳佳 记者 宁迪)5月15日,“京东618惊喜开放日”...
证监会正式对外公布实施修订后的... 转自:北京商报北京商报讯(记者 马换换 王蔓蕾)5月16日晚间,证监会官网发文称,《关于修改<上市公...
调研速递|神州泰岳接受超百家投... 5月16日下午15:00 - 17:00,北京神州泰岳软件股份有限公司在全景网“投资者关系互动平台”...
美股异动 | 哔哩哔哩(BIL... 周五,哔哩哔哩(BILI.US)涨6%,报18.81美元。消息面上,哔哩哔哩将于5月20日(即下周二...
中国通信服务全资子公司中标一项... (转自:快查一企业中标了)快查APP显示,中国通信服务相关公司江西省通信产业服务有限公司于2025年...
微软就“解绑”Teams与Of... 欧盟委员会5月16日宣布,微软已提出一系列新承诺,旨在了结有关将Teams与Office产品捆绑销售...
多少人愿买高价“美国货”? 制... 转自:新华社 “美国制造”商品究竟贵多少?有多少美国消费...
一互联网“大厂”餐饮专家收受供... 中国青年报客户端讯(中青报·中青网记者 刘言)一互联网“大厂”餐饮专家利用职务之便,3年收受供应商贿...
香港今年首季经济稳健扩张 全年... 中新网香港5月16日电 (魏华都 黄岩妮)香港特区政府16日举行记者会,介绍今年第一季度香港经济及今...