《理解 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 ...
随机推荐
- 16.10.17学到的Java知识
1. 例:3-2.6==0.4的值是什么?可能乍一看,感觉是返回TRUE,因为3-2.6=0.4,0.4==0.4:所以返回TRUE. 然而,上面分析在JAVA中是错的. 由于浮点数的运算在JAVA中 ...
- 【转】Oracle Database PSU/CPU
转自: http://www.cnblogs.com/ebs-blog/archive/2011/07/28/2167232.html 1. 什么是PSU/CPU?CPU: Critical Patc ...
- MVC 前台向后台传输数据
今天,我们一起来学习下.MVC如何在前台给后台传输数据 (1)前台传输数据到后台 具体思路:前台拼凑json字符串,然后通过 get 或 post 方式,传递到后台 Action 方法中 我现在前台展 ...
- c#datagirdview ,用DataSource 方式赋值,然后更新出问题问题
先说一下程序 主窗体 ,两个子窗体A,B.嵌入主窗体的Panel里边 主窗体,启动类C里边的查找方法,查到的值,通过事件委托送到窗体A C类里同时修改查询表,把修改的查询表通过事件委托发送给窗体B, ...
- 20145202、20145225、20145234 《信息安全系统设计基础》实验五 简单嵌入式WEB 服务器实验
实验内容 1.配置环境 2.使用vi 编辑器阅读理解源码 2.编译应用程序 运行 make 产生可执行文件httpd 3.下载调试 使用 NFS 服务方式将HTTPD 下载到开发板上,并拷贝测试用的网 ...
- [转]了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密_Mr_Indigo的空间
了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密 关系型数据库,如SQL Server,使用锁来避免多用户修改数据时的并发冲突.当一组数据被某个用户锁定时,除非第一个用户结束修 ...
- bx、si、di 和 bp
bx.si.di 和 bp 在 8086CPU 中,只有这 4 个寄存器可以用在 "[...]" 中来进行内存单元的寻址. mov ax, [bx] mov ax, [bx+si] ...
- 【转】Beanstalkd 队列简易使用
Beanstalkd一个高性能分布式内存队列系统 之前在微博上调查过大家正在使用的分布式内存队列系统,反馈有Memcacheq,Fqueue, RabbitMQ, Beanstalkd以及link ...
- [转]JUnit-4.11使用报java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing错误
原文引自: http://blog.csdn.net/castle07/article/details/8553704 今天尝试使用JUnit,下载了最新的JUnit版本,是4.11,结果尝试使用发现 ...
- JQuery延时操作
JQuery通过setTimeout函数可以实现延时操作以完成在编程达到某些需要的效果. 使用方法如下: function doSomething() { alert("hello worl ...