为什么需要尾调用优化?
function outerFunction() {
return innerFunction()
}
在Es6之前,上面例子在内存中会发生如下操作
- 执行到outerFunction函数体,第一个栈帧被推到栈上.
- 执行到outerFunction函数return语句.必须先计算innerFunction函数.
- 执行innerFunction函数体,第二个栈帧被推到栈上.
- 执行innerFunction函数,计算返回值.
- 将返回值传给outerFunction,然后ounterFunction在返回值.
- 将栈帧弹出栈外.
Es6以后所作优化
- 执行到outerFunction函数体,第一个栈帧被推到栈上.
- 执行到outerFunction函数return语句.必须先计算innerFunction函数.
- 引擎发现把第一个栈帧弹出栈外也没问题,因为outerFunction的返回值也是innerFunction的返回值
- 将outerFunction弹出栈外
- 执行到innerFunction函数体,栈帧被推到栈上.
- 执行innerFunction函数,计算返回值
- 将innerFunction的栈帧弹出栈外
第二种相比较第一种的优化点
第一种情况下,每次多调用一次嵌套函数,就会多增加一个栈帧.而第二种,无论调用多少次嵌套函数,都只有一个栈帧.
怎样才算是尾调用优化?
- 代码在严格模式下执行
- 外部函数的返回值是对尾部函数的调用
- 尾调用函数返回后不需要执行额外的逻辑
- 尾调用函数不是应用外部函数作用域中自由变量的闭包
同时满足以上条件才能称为尾调用优化
错误例子
"use strict"
// 无优化,尾调用没有返回
function outerFunction() {
innerFunction()
}
// 无优化,尾调用没有直接返回
function outerFunction() {
let innerFunctionResult = innerFunction()
return innerFunctionResult
}
// 无优化,尾调用是一个闭包
function outerFunction() {
let foo = "bar"
function = innerFunction() {
return foo
}
return innerFunction()
}
// 无优化,返回后需要执行额外的逻辑,转字符串
function onterFunction() {
return innerFunction().toString()
}
再来几个正确的例子
"use strict"
// 有优化: 栈帧销毁钱执行参数计算
function onterFunction(a , b) {
return innerFunction(a + b)
}
// 有优化: 初始返回值不设计栈帧
function outerFunction(a, b) {
if (a < b) {
return a
}
return innerFunction(a + b)
}
(学习笔记:JavaScript高级程序设计第四版---10.13 尾调用优化)
想详细了解的小伙伴可以自己去翻阅