在读 《深入理解ES6》一书中,看到有关函数的 “尾调用优化” 章节,特此记录一下
尾调用 指的是 函数作为另一个函数的最后一条语句被调用:
function foo () { return bar(); }
书中说 在 ES5 的时候,尾调用的实现与其他函数调用类型,创建一个新的帧栈,然后将它推入调用栈表示调用,也就是说在循环调用中,每个未执行完的帧栈都保存在内存中,当调用栈变的过大会造成性能问题.
ES6 的优化
严格模式下,缩减了尾调用栈的大小;非严格模式不受影响,如果满足以下条件,尾调用不再创建新的帧栈,而是服用当前帧栈.
-
尾调用不访问当前帧栈的变量(非闭包)
-
在函数内部,尾调用是最后一条语句
-
尾调用的值作为结果返回
看如下例子:
// 可以优化 "use strict"; function foo() { return bar(); }
// 无法优化 -> 函数调用没有作为值返回;
function foo() {
bar();
}
// 无法优化 -> 此处 函数并没有直接被返回,而是执行了一步操作 "use strict"; function foo() { return 1 + bar(); }
// 无法优化 -> 调用不在尾部 function foo() { var result = bar(); return result; }
// 无法优化,闭包! "use strict"; function foo() { var num = 1, getNum = () => num; return getNum(); }
因为尾调用优化是执行在JS 引擎上的优化,在我们实际的开发中的应用场景是什么呢?
场景1: 获取一个固定格式的日期
function getDate() { return createDateTime(true); } function getTime() { return createDateTime(false); } function createDateTime(date) { // ... return date ? 'YY-MM-DD':'YY-MM-DD hh:mm:ss' }
场景2:递归
function factorial(n,p=1) { if(n <= 1) { return n*p; }else { let result = n * p; return factorial(n-1,result); } }