js函数式编程——蹦床函数
概述
这是我在学习函数式编程的时候,关于递归,尾递归,相互递归和蹦床函数的一些心得,记下来供以后开发时参考,相信对其他人也有用。
参考资料:JavaScript玩转Clojure大法之 - Trampoline
递归
我们知道,es5是没有尾递归优化的,所以在递归的时候,如果层数太多,就会报“Maximum call stack size exceeded”的错误。就连下面这个及其简单的递归函数都会报“Maximum call stack size exceeded”的错误。
function haha(a) {
if(!a) return a;
return haha(a-1);
}
haha(100); //输出0
haha(12345678); //输出“Maximum call stack size exceeded”
为什么会报“Maximum call stack size exceeded”的错误?我觉得原因是在每次递归调用的时候,会把当前作用域里面的基本类型的值推进栈中,所以一旦递归层数过多,栈就会溢出,所以会报错。
注意:
- js中的栈只会储存基本类型的值,比如:number, string, undefined, null, boolean。
- 为什么在调用下一层递归函数的时候没有释放上一层递归函数的作用域?因为在回来的时候还需要用到里面的变量。
尾递归
怎么优化上面的情况呢?方法是使用尾递归。有尾递归优化的编译器会把尾递归编译成循环的形式,如果没有尾递归优化,那就自己写成循环的形式。如下面的例子所示:
//尾递归函数,返回一个函数调用,并且这个函数调用是自己
function haha(a, b) {
if(b) return b;
return haha(a, a-1);
}
//优化成循环的形式
function yaya(a) {
let b = a;
while(b) {
b = b - 1;
}
}
需要注意的是,看上面尾递归的代码,有一点很重要,就是用一个b变量来存上一次递归的值。这是尾递归常用的方法。另外,其实上面尾递归的代码不需要变量b,但为了便于说明,所以我加上了变量b。
相互递归
但是关于递归还有一种形式,就是相互递归,如下面的代码所示:
function haha1(a) {
if(!a) return a;
return haha2(a-1);
}
function haha2(a) {
if(!a) return a;
return haha1(a-1);
}
haha1(100); //输出0
haha1(12345678); //输出Maximum call stack size exceeded
可以看到,当相互递归层数过多的时候,也会发生栈溢出的情况。
蹦床函数
蹦床函数就是解决上面问题的方法。
首先我们改写上面的相互递归函数:
function haha1(a) {
if(!a) return a;
return function() {
return haha2(a-1);
}
}
function haha2(a) {
if(!a) return a;
return function() {
return haha1(a-1);
}
}
这个改写就是建立一个闭包来封装相互递归的函数,它的好处是由于不是直接的相互递归调用,所以不会把上一次的递归作用域推进栈中,而是把封装函数储存在堆里面,利用堆这个容量更大但读取时间更慢的储存形式来替代栈这个容量小但读取时间快的储存形式,用时间来换取空间。
我们尝试使用一下上面的函数:
haha1(3)(); //输出一个函数
haha1(3)()()(); //输出0
通过上面的示例可以看到,如果参数不是3而是很大的一个数字的时候,我们就需要写很多个括号来实现调用很多次。为了简便,我们可以把这种调用形式写成函数,这就是蹦床函数。如下所示:
function trampoline(func, a) {
let result = func.call(func, a);
while(typeof result === 'function') {
result = result();
}
return result;
}
基本原理是一直调用,直到返回值不是一个函数为止。
最后来使用蹦床函数:
trampoline(haha1, 12345678); //过一会儿就输出0
由于储存在堆中,所以耗时较长,过了一会儿才会输出0,但是并没有报栈溢出的错误。
js函数式编程——蹦床函数的更多相关文章
- Python进阶之函数式编程(把函数作为参数)
什么是函数式编程? 什么是函数式编程? 函数:function 函数式:functional,一种编程范式 函数式编程是一种抽象计算的编程模式 函数≠函数式,比如:计算≠计算机 在计算机当中,计算机硬 ...
- js函数式编程(一)-纯函数
我将写的第一个主题是js的函数式编程,这一系列都是mostly adequate guide这本书的读书总结.原书在gitbook上,有中文版.由于原作者性格活泼,书中夹杂很多俚语,并且行文洒脱.中文 ...
- js函数式编程术语总结 - 持续更新
参考文档1 参考文档2 函数式编程术语 高阶函数 Higher-Order Functions 以函数为参数的函数 返回一个函数的函数 函数的元 Arity 比如,一个带有两个参数的函数被称为二元函数 ...
- js函数式编程(二)-柯里化
这节开始讲的例子都使用简单的TS来写,尽量做到和es6差别不大,正文如下 我们在编程中必然需要用到一些变量存储数据,供今后其他地方调用.而函数式编程有一个要领就是最好不要依赖外部变量(当然允许通过参数 ...
- JS函数式编程 - 概念
最近在看Typescript,顺便看了一些函数式编程,然后半个国庆假期就没有了.做个笔记,分几个部分写吧. 最开始接触函数式编程的时候,第一个接触的概念就是高阶函数,和柯里化.咋一看,这不就是长期用来 ...
- js函数式编程
最近在看朴灵的<深入浅出nodejs>其中讲到函数式编程.理解记录下 高阶函数 比较常见,即将函数作为参数,或是将函数作为返回值得函数. 如ECMAScript5中提供的一些数组方法 fo ...
- 1.python函数式编程-map函数
编程方法论 面向过程 函数式 面向对象 面向过程 将编程过程拆分成多个步骤,在函数中按照每个步骤进行编程: 函数式编程 编程语言定义的函数+数学意义的函数 1.不可变,不用变量保存状态,不修改变量: ...
- day16-python之函数式编程匿名函数
1.复习 #!/usr/bin/env python # -*- coding:utf-8 -*- name = 'alex' #name=‘lhf’ def change_name(): name= ...
- [Python3] 036 函数式编程 返回函数
目录 函数式编程 之 返回函数 1. 引子 2. 闭包 closure 函数式编程 之 返回函数 函数可以返回具体的值 也可以返回一个函数作为结果 1. 引子 1.1 定义一个普通函数 >> ...
随机推荐
- BOUNDARIES AND SPACE
BOUNDARIES AND SPACE Review Nice work! You've learned a lot. Let's review the web and CSS concepts c ...
- java学习-- equals和hashCode的关系
hashcode的目的就是在hashset或者hashmap等中比较两个对象相等时,减少equals的使用次数来提高效率 以下为摘录 java中hashcode和equals的区别和联系 HashSe ...
- MySQL的show profile(已过时)简介以及该功能在MySQL 5.7中performance_schema中的替代
本文出处:http://www.cnblogs.com/wy123/p/6979499.html show profile 命令用于跟踪执行过的sql语句的资源消耗信息,可以帮助查看sql语句的执行情 ...
- spring cloud 笔记
1.在工程的启动类中,通过@EnableDiscoveryClient向服务中心注册:并且向程序的ioc注入一个bean: restTemplate;并通过@LoadBalanced注解表明这个res ...
- Shiro HashedCredentialsMatcher 认证匹配
Shiro 提供了用于加密密码和验证密码服务的 CredentialsMatcher 接口,而 HashedCredentialsMatcher 正是 CredentialsMatcher 的一个实现 ...
- Java获取工程目录
背景:程序执行时,会涉及到去读取配置文件等操作,那就需要了解怎么获得文件路径 Java目录映射关系 说明一点:在Java代码执行时,会将编译生成的classes文件,以及配置文件等信息生成到tar ...
- hdu 1277 AC自动机入门(指针版和数组版)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1277 推荐一篇博客(看思路就可以,实现用的是java): https://www.cnblogs.co ...
- php curl请求回来的中文为乱码
在浏览器访问回来的编码格式是正常的,但是从php curl 请求过来的确实乱码,之前也试过这个函数好像不行,今天吧最后一个参数换了,简单粗暴,可以了mb_convert_encoding($res, ...
- 小姐姐手把手教你JS数组中的对象去重
有时候数据库中的数据重复的,我们另一个需求需要数据的唯一性 那么这时候就用到这个方法了 我还是以截图的方式发粗来 不然太丑了 见谅 console.log(map)打印出来的结果已经帮我们把需要的 ...
- linux rescue 修复引导 与linux下修复windows引导
在windows有引导的情况下修复linux引导 插入U盘启动 进入rescue模式 fdisk -l 查看分区情况 chroot /mnt/sysimage/ 进入系统 grub-install / ...