es6函数之尾调用优化实例分析


Posted in Javascript onApril 25, 2020

本文实例讲述了es6函数之尾调用优化。分享给大家供大家参考,具体如下:

什么是尾调用优化?

尾调用是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。

function f(x) {
 return g(x)
}

上面代码中,函数f的最后一步是调用函数g,这就叫尾调用。

以下三种情况,都不属于尾调用。

// 情况一
function f(x) {
 let y = g(x)
 return y
}
// 情况二
function f(x) {
 return g(x) + 1
}
// 情况三
function f(x) {
 g(x)
}

尾调用不一定出现在函数尾部,只要是最后一步操作即可。

function f(x) {
 if (x > 0) {
  return m(x)
 }
 return n(x);
}

尾调用之所以与其他调用不同,就在于它的特殊的调用位置。

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

尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置,内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了。

function f() {
 let m = 1;
 let n = 2;
 return g(m + n);
}
f();

// 等同于
function f() {
 return g(3);
}
f();

// 等同于
g(3);

上面代码中,如果函数g不是尾调用,函数f就需要保存内部变量m和n的值、g的调用位置等信息。但由于调用g之后,函数f就结束了,所以执行到最后一步,完全可以删除f(x)的调用帧,只保留g(3)的调用帧。

这就叫做“尾调用优化”(Tail call optimization),即只保留内层函数的调用帧。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用帧只有一项,这将大大节省内存。这就是“尾调用优化”的意义。

注意,只有不再用到外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧,否则就无法进行“尾调用优化”。

function addOne(a){
 var one = 1;
 function inner(b){
  return b + one;
 }
 return inner(a);
}

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
date.parse在IE和FF中的区别
Jul 29 Javascript
使用js如何实现全选与全不选
Dec 30 Javascript
js获取下拉列表框中的value和text的值示例代码
Jan 11 Javascript
js字符串操作方法实例分析
May 06 Javascript
JavaScript使用DeviceOne开发实战(二) 生成调试安装包
Dec 01 Javascript
Javascript之String对象详解
Jun 08 Javascript
AngularJS入门教程之链接与图片模板详解
Aug 19 Javascript
详解Vue 动态添加模板的几种方法
Apr 25 Javascript
angular实现spa单页面应用实例
Jul 10 Javascript
babel之配置文件.babelrc入门详解
Feb 22 Javascript
Vue组件之极简的地址选择器的实现
May 31 Javascript
详解Vue路由自动注入实践
Apr 17 Javascript
es6函数之尾递归用法实例分析
Apr 25 #Javascript
javascript 易错知识点实例小结
Apr 25 #Javascript
javascript执行上下文、变量对象实例分析
Apr 25 #Javascript
JavaScript ECMA-262-3 深入解析(二):变量对象实例详解
Apr 25 #Javascript
JavaScript ECMA-262-3 深入解析(一):执行上下文实例分析
Apr 25 #Javascript
使用 Jest 和 Supertest 进行接口端点测试实例详解
Apr 25 #Javascript
javascript 函数的暂停和恢复实例详解
Apr 25 #Javascript
You might like
给初学者的30条PHP最佳实践(荒野无灯)
2011/08/02 PHP
php实现自定义中奖项数和概率的抽奖函数示例
2017/05/26 PHP
ThinkPHP类似AOP思想的参数验证的实现方法
2019/12/18 PHP
几个高效,简洁的字符处理函数
2007/04/12 Javascript
JavaScript在IE和Firefox(火狐)的不兼容问题解决方法小结
2010/04/13 Javascript
精心挑选的15款优秀jQuery 本特效插件和教程
2012/08/06 Javascript
jquery select多选框的左右移动 具体实现代码
2013/07/03 Javascript
jquery将一个表单序列化为一个对象的方法
2013/12/02 Javascript
JavaScript面向对象之私有静态变量实例分析
2016/01/14 Javascript
jQuery实现的表格前端排序功能示例
2017/09/18 jQuery
vue插件开发之使用pdf.js实现手机端在线预览pdf文档的方法
2018/07/12 Javascript
node.js express捕获全局异常的三种方法实例分析
2019/12/27 Javascript
jQuery实现容器间的元素拖拽功能
2020/12/01 jQuery
三剑客:offset、client和scroll还傻傻分不清?
2020/12/04 Javascript
[05:01]3.19DOTA2发布会 我们都是刀塔人
2014/03/25 DOTA
[55:03]完美世界DOTA2联赛PWL S2 LBZS vs FTD.C 第二场 11.20
2020/11/20 DOTA
在Django中编写模版节点及注册标签的方法
2015/07/20 Python
从源码解析Python的Flask框架中request对象的用法
2016/06/02 Python
解析Python中的__getitem__专有方法
2016/06/27 Python
Python实现两个list对应元素相减操作示例
2017/06/09 Python
python绘制条形图方法代码详解
2017/12/19 Python
Python爬虫学习之翻译小程序
2019/07/30 Python
pandas 对日期类型数据的处理方法详解
2019/08/08 Python
python输出pdf文档的实例
2020/02/13 Python
通过python检测字符串的字母
2020/02/18 Python
Python爬虫与反爬虫大战
2020/07/30 Python
css3+伪元素实现鼠标移入时下划线向两边展开的效果
2017/04/25 HTML / CSS
联想墨西哥官方网站:Lenovo墨西哥
2016/08/17 全球购物
《桃花心木》教学反思
2014/02/17 职场文书
期末学生评语大全
2014/04/24 职场文书
公司副总经理任命书
2014/06/05 职场文书
2015年法院工作总结范文
2015/04/28 职场文书
酒桌上的开场白
2015/06/01 职场文书
《我们的民族小学》教学反思
2016/02/19 职场文书
postgres之jsonb属性的使用操作
2021/06/23 PostgreSQL
详解nginx安装过程并代理下载服务器文件
2022/02/12 Servers