Ecmascript 6 绑定函数是否支持ES6中正确的尾部调用?

Ecmascript 6 绑定函数是否支持ES6中正确的尾部调用?,ecmascript-6,language-lawyer,tail-call-optimization,tail-call,Ecmascript 6,Language Lawyer,Tail Call Optimization,Tail Call,在ECMAScript 2015语言规范中,和的定义都包括“Perform PrepareForTailCall()”作为其步骤之一,因此我们知道这些函数支持正确的尾部调用(即尾部调用优化) 但是,的定义省略了PrepareForTailCall()。这是否意味着绑定函数不支持正确的尾部调用,并且递归调用自身的绑定函数可能会破坏堆栈?请参见§12.3.4.1()。首先,我们执行IsInTailPosition,然后执行EvaluatedDirectCall——结果是F.[Call]]。换句话说,

在ECMAScript 2015语言规范中,和的定义都包括“Perform PrepareForTailCall()”作为其步骤之一,因此我们知道这些函数支持正确的尾部调用(即尾部调用优化)

但是,的定义省略了PrepareForTailCall()。这是否意味着绑定函数不支持正确的尾部调用,并且递归调用自身的绑定函数可能会破坏堆栈?

请参见§12.3.4.1()。首先,我们执行
IsInTailPosition
,然后执行
EvaluatedDirectCall
——结果是
F.[Call]]
。换句话说,当我们真正打电话的时候,我们已经知道我们是否处于尾端

然而,正如您所提到的,JS是,除了Safari

绑定函数对象上的
[[Call]]
定义忽略了
PrepareForTailCall()
。这是否意味着绑定函数不支持正确的尾部调用,并且绑定函数递归调用自身可能会破坏堆栈

否。
PrepareForTailCall
发生在中,它检查表达式是否处于尾部位置。准备尾部调用时,当前正在运行的执行上下文将被丢弃,然后函数将在相应的
[[call]]
内部方法上进行调度。新的运行执行上下文是从中设置的。在这种情况发生之前,它引入了一个额外的间接层次

在ECMAScript 2015语言规范中,
Function.prototype.apply
Function.prototype.call
的定义都包括“Perform
PrepareForTailCall()
”作为其步骤之一,因此我们知道这些函数支持正确的尾部调用

是的,这是必要的,因为设置了新的运行执行上下文(用于“实现定义的步骤”)。在调用实际函数之前,
PrepareForTailCall
将删除此“内置上下文”


call
apply
方法是调用函数的函数,当调用它们时,堆栈上有两个调用需要进行尾部调用优化。(与此相反,例如,
Array.prototype.map
,后者也调用其他函数,但此处的
map
执行上下文保留在调用堆栈上。在
call
apply
中,
call()
确实位于算法的尾部位置).

N.B.我知道实际上很少有JS解释器支持正确的尾部调用;这是关于规范的问题,而不是关于实际实现的问题。不,当对绑定函数调用[[Call]]时,prepareForTailCall已经完成