尾调用
尾调用是指函数作为另一个函数的最后一条语句被调用
function doA(){
return doB();
}
在es5中,尾调用的实现是创建一个新的stack frame,将其推入调用栈中表示函数调用。所以,每一个未用完的 stack frame 都会保存在内存中,当调用栈变得特别大,程序就不好了
ESMAScript 6 尾调用优化
es6 严格模式下(非严格模式不受影响),满足一下三个条件,尾调用不再创建新的stack frame ,而是重用当前 stack frame
- 函数不是一个闭包
- 在函数内部,尾调用是最后一条语句
尾调用的结果作为函数值返回
'use strict'; function doA(){ //优化后 return doB(); }
以下情况是不会优化的
'use strict';
function doA(){
//没有作为函数值返回,不会优化
doB();
}
'use strict';
function doA(){
var res = 1;
//func调用了另一个函数作用域内变量,func是闭包,不会优化
func = () => res;
return func();
}
'use strict';
function doA(){
//在返回结果前+1,不会优化
return 1 + doB();
}
'use strict';
function doA(){
//调用不在尾部,无法优化
let res = doB();
return res;
}
利用尾调用优化
尾调用的优化发生在引擎背后,除非是要优化一个函数,否则不必考虑。
递归函数是最主要应用的场景。如果递归函数的计算量足够大,尾调用优化可以大大提升程序性能
function factorial(n) {
if( n <= 1 ) {
return 1;
} else {
//无法优化,必须在执行返回结果后进行乘法
return n * factorial(n-1);
}
优化后
function factorial(n, p = 1) {
if( n <= 1 ) {
return 1 * p;
} else {
let res = n * p;
return factorial(n - 1, res);
}
本文摘于 《深入理解es6》密码:e2y2