《理解 ES6》阅读整理:函数(Functions)(八)Tail Call Optimization
尾调用优化(Tail Call Optimization)
尾调用是指函数的最后一条语句是函数调用,比如下面的代码:
function doSomething() {
return doSomethingElse();
}
在ES5中,尾调用和其他形式的函数调用一样:脚本引擎创建一个新的函数栈帧并且压在当前调用的函数的栈帧上面。也就是说,在整个函数栈上,每一个函数栈帧都会被保存,这有可能造成调用栈占用内存过大甚至溢出。
尾递归在ES6中有何不同(How Tail Call are Different in ECMAScript6)
在ES6中,strict模式下,满足以下条件,尾调用优化会开启,此时引擎不会创建一个新的栈帧,而是清除当前栈帧的数据并复用:
(1、尾调用函数不需要访问当前栈帧中的变量
(2、尾调用返回后,函数没有语句需要继续执行
(3、尾调用的结果就是函数的返回值
下面例子中的函数就可以使用尾调用优化:
"use strict";
function doSomething() {
return doSomethingElse();
}
然而下面例子中的函数不能使用尾调用优化,因为尾调用的结果不是函数的返回值:
"use strict";
function doSomething() {
doSomethingElse();
}
尾调用返回后,如果函数仍然有语句要执行,也是不能使用尾调用优化的:
"use strict";
function doSomething() {
return 1 + doSomethingElse();
}
尾调用函数如果是闭包函数,也不能使用尾调用优化:
"use strict";
function doSomething() {
var num = 1;
var func = () => num;
return func();
}
如何利用尾调用优化(How to Harness Tail Call Optimization)
尾调用优化主要用在递归函数中,通常能带来显著的效果。看一个递归计算阶乘的函数:
function factorial(n) {
if (n <= 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
很明显,上面的代码并不能使用尾调用优化,因为factorial(n-1)返回后,仍然有语句要继续执行。但是我们可以改写这个函数,使其能够利用尾调用优化特性:
function factorial(n, p = 1) {
if (n <= 1) {
return 1 * p;
} else {
let result = n * p;
return factorial(n - 1, result);
}
}
如和改写递归函数以便利用尾调用优化是需要技巧的。如果可以,应该充分利用引擎的尾调用优化特性来优化递归函数。
《理解 ES6》阅读整理:函数(Functions)(八)Tail Call Optimization的更多相关文章
- 《理解 ES6》阅读整理:函数(Functions)(五)Name Property
名字属性(The name Property) 在JavaScript中识别函数是有挑战性的,因为你可以使用各种方式来定义一个函数.匿名函数表达式的流行使用导致函数调试困难,在栈信息中难以找出函数名. ...
- 《理解 ES6》阅读整理:函数(Functions)(一)Default Parameter Values
对于任何语言来说,函数都是一个重要的组成部分.在ES6以前,从JavaScript被创建以来,函数一直没有大的改动,留下了一堆的问题和很微妙的行为,导致在JavaScript中使用函数时很容易出现错误 ...
- 深入理解ES6箭头函数中的this
简要介绍:箭头函数中的this,指向与一般function定义的函数不同,比较容易绕晕,箭头函数this的定义:箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定. 1.何为定义时 ...
- ES6 入门系列 - 函数的扩展
1函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法. function log(x, y) { y = y || 'World'; console.log( ...
- es6中的函数
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面. function log(x, y = 'World') { console.log(x, y); } log('Hello') // ...
- asp.net MVC helper 和自定义函数@functions小结
asp.net Razor 视图具有.cshtml后缀,可以轻松的实现c#代码和html标签的切换,大大提升了我们的开发效率.但是Razor语法还是有一些棉花糖值得我们了解一下,可以更加强劲的提升我们 ...
- asp.net MVC 自定义@helper 和自定义函数@functions小结
asp.net Razor 视图具有.cshtml后缀,可以轻松的实现c#代码和html标签的切换,大大提升了我们的开发效率.但是Razor语法还是有一些棉花糖值得我们了解一下,可以更加强劲的提升我们 ...
- 《javascript个人理解,个人整理。》
万事开头难. 本人做前端工程师,已几年,没有特别大的,已文字方式去做总结. 前段时间,早已经想好,但是迟迟没有去下笔!好在现在陆陆续续的写下去. 我知道这是一个很大的工程,但是我还是想做下去,不为别的 ...
- ES6知识整理(4)--数组的扩展
最近工作比较忙,基本每天都会加班到很晚.处理一些客户端兼容问题以及提升用户体验的优化.也将近一周没更文了,现在继续es6的学习总结. 上篇回顾 ES6知识整理(三)--函数的扩展 扩展运算符 形式是3 ...
随机推荐
- Win10下Android studio配置
Win10下Android studio配置 一.安装Android Studio的准备工作 1.下载好JDK,去官网上找一个下载下来 2.安装JDK.并配置环境变量.安装过程:本人将使用的是jdk- ...
- MySQL高级查询语句
高级查询: 一:多表连接 1.select Info.Code,Info.Name,Nation.Name from Info,Nation where Info.Nation = Nation.Co ...
- 【openresty】向lua代码中传递参数
前面介绍FormInputNginxModule模块时,明白了openresty如何获取post提交的数据. 然后,如果需要通过lua处理这些数据,需要把数据作为参数传递到lua中,lua获取了这些数 ...
- github中cesium-terrain-builder和cesium-terrain-server使用
cesium-terrain-builder的使用: 这个是用来把含有高程数据的tif图片切片成.terrain的小文件,是给cesium-terrain-server提供服务的. cesium-te ...
- JAVA可移植性广泛应用
一.JAVA作为一种编程语言:源代码可移植性 作为一种编程语言,JAVA提供了一种最简单同时也是人们最熟悉的可移植性–源代码移植.这意味着任意一个JAVA程序,不论它运行在何种CPU.操作系统或JAV ...
- 强大的Spring缓存技术(中)
好,到目前为止,我们的 spring cache 缓存程序已经运行成功了,但是还不完美,因为还缺少一个重要的缓存管理逻辑:清空缓存. 当账号数据发生变更,那么必须要清空某个缓存,另外还需要定期的清空所 ...
- 一起买beta版PHP单元测试
一起买beta版PHP单元测试 测试目的 保证代码质量,对各个单元进行测试,可以有效地保证代码的可靠性,让模块在与别的模块整合时出现更少的错误. 单元描述 完成帖子接口 将"正在进行&q ...
- eclipse中java项目的build path详解
BuildPath中只支持加入jar文件,具体方法如下:在eclips里在工程名上右键->build path->contigure bud path->java build pat ...
- oracle 秒
select case when deptno=10 then 'aaaa' when deptno=20 then 'bbbb' when deptno=30 then 'cccc' e ...
- README
README 在用户中心设置简体中文. 在版本库找到你的工程点击进入. 在版本库地址里复制 http 开头的地址. 在本地进入要clone的文件夹,用git clone(如果是空的仓库直接clone, ...