ES6包含了一个性能领域的特殊要求。这与一个涉及函数调用的特定优化形式相关:即尾调用优化(Tail Call Optimization,TCO)。简单地说,尾调用就是一个出现在另一个函数“结尾”处的函数调用。这个调用结束之后就没有其余事情要做了(除了可能要返回结果值)
什么尾调用
举个例子,下面是一个非递归的尾调用:
function foo(x) { return x } // 尾调用 function bar(y) { return foo(y + 1) } // 非尾调用 function baz() { return 1 + bar(40) } baz() // 输出42
说明: foo(y+1) 是 bar(...) 中的尾调用,因为在 foo(...) 完成后, bar(...) 也完成了,并且只需要返回 foo(...) 调用的结果。然而, bar(40) 不是尾调用,因为在它完成后,它的结果需要加上1才能由 baz() 返回。
在JavaScript里,调用一个新的函数需要额外的一块预留内容来管理调用栈,成为栈帧。所以前面的代码一般会同时需要为每个 baz() 、 bar(...) 、 foo(...) 保留一个栈帧。
然而,如果支持TCO的引擎能够意识到 foo(y+1) 调用位于尾部,这意味着 bar(...) 基本上已经完成了,那么在调用 foo(...) 时,它就不需要创建一个新的帧栈,而是可以重用已有的 bar(...) 的帧栈。这样不仅速度快,而且节省内存。
什么是尾递归
在计算机科学里,尾调用是指一个函数里的最后一个动作是一个函数调用的情形:即这个调用的返回值直接被当前函数返回的情形。这种情形下称该调用位置为尾位置。若这个函数在尾位置调用本身(或是一个尾调用本身的其他函数等等),则称这种情况为尾递归,是递归的一种特殊情形。尾调用不一定是递归调用,但是尾递归特别有用,也比较容易实现。
TCO的意义
在程序运行时,计算机会为应用程序分配一定的内存空间;应用程序则会自行分配所获得的内存空间,其中一部分被用于记录程序中正在调用的各个函数的运行情况,这就是函数的调用栈。常规的函数调用总是会在调用栈最上层添加一个新的堆栈帧(stack frame,也翻译为“栈帧”或简称为“帧”),这个过程被称作“入栈”或“压栈”(意即把新的帧压在栈顶)。当函数的调用层数非常多时,调用栈会消耗不少内存,甚至会撑爆内存空间(栈溢出),造成程序严重卡顿或意外崩溃。尾调用的调用栈则特别易于优化,从而可减少内存空间的使用,也能提高运行速度。其中,对尾递归情形的优化效果最为明显,尤其是递归算法非常复杂的情形。
在简单的代码片段中,这类优化算不了什么,但是在处理递归时,这就解决了大问题,特别是如果递归可能会导致成千上百个栈帧的时候。有了TCO,引擎可以用同一个栈帧执行所有的这类调用!
递归是 JavaScript 中一个纷繁复杂的主题。因为如果没有TCO的话,引擎需要实现一个随意的限制来界定递归栈的深度,达到了就得停止,以防止内存耗尽。有了TCO,尾调用的递归函数本质上就可以任意运行,因为再也不需要使用额外的内存,也没有了内存溢出的问题。
下面用尾递归实现一个典型的阶乘函数:
// 用循环实现 function factorial(n) { if (n<2) return 1 var res = 1 for (var i = n; i > 1; i--) { res *= i } return res } // 用尾递归实现 function factorial(n) { function fact(n, res) { if (n < 2) return res return fact(n-1, n*res) } return fact(n, 1) } factorial(5) // 输出120
注意:TCO只用于有实际的尾调用的情况,如果你写了一个没有尾递调用的函数,那么性能还是会回到普通帧栈分配的情形,引擎对这样的递归调用栈的限制也仍然有效。
总结
一般来说,尾调用消除是可选的,可以用,也可以不用。然而,在函数编程语言中,语言标准通常会要求编译器或运行平台实现尾调用消除。这让程序员可以用递归取代循环而不丧失性能。ES6之所以要求引擎实现TCO而不是将其留给引擎自由决定,一个原因是缺乏TCO会导致一些JavaScript算法因为害怕调用栈限制而降低了通过递归实现的概率。
如果在所有的情况下引擎缺乏TCO只是降低了性能,那它就不会成为ES6所要求的东西。但是,由于缺乏TCO确实可以使一些程序变得无法实现,所以它就成为了一个重要的语言特性而不是隐藏的实现细节。ES6确保了JavaScript开发者从现在开始可以在所有符合ES6+的浏览器中依赖这个优化。这对JavaScript性能来说是一个胜利。
参考文献
《你不知道的JavaScript-中卷》
ES6,尾调用优化
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新动态
- 梅艳芳.1994-是这样的(金碟版)【华星】【WAV+CUE】
- 张学友《真情流露》HQ+S纯银深度[低速原抓WAV+CUE]
- 江志丰2012-七天[豪记][WAV+CUE]
- 黑鸭子2003《聆听柔情HQCD》[日本版][WAV+CUE]
- 群星《奔赴!万人现场 第5期》[FLAC/分轨][587.07MB]
- 关大洲《国家宝藏 第四季原声音乐 关大洲作品》[320K/MP3][109.49MB]
- 关大洲《国家宝藏 第四季原声音乐 关大洲作品》[FLAC/分轨][527.23MB]
- LOL双城之战大乱斗什么时候更新 双城大乱斗上线更新时间介绍
- s14全球总决赛冠军皮肤有什么 2024T1冠军皮肤选择一览
- faker加里奥s14决赛什么出装 faker加里奥s14决赛出装介绍
- 《马里奥与路易吉RPG:兄弟齐航》Fami通34分:路易吉存在感拉满
- 数据挖掘者新发现:NS继任机型或支持4K分辨率
- 宫本茂谈任天堂未来:研发费用增加但注重创意与传承
- 陈小云.2000-餐厅综艺金榜【海丽唱片】【WAV+CUE】
- 卓文萱.2008-翻滚吧!蛋炒饭电视原声带【滚石】【FLAC分轨】