简体   繁体   中英

Do bound functions support proper tail calls in ES6?

In the ECMAScript 2015 Language Specification, the definitions of Function.prototype.apply and Function.prototype.call both include "Perform PrepareForTailCall()" as one of their steps, so we know that these functions support proper tail calls (ie, tail call optimisation).

The definition of [[Call]] on bound function objects , however, omits PrepareForTailCall(). Does this mean that bound functions do not support proper tail calls, and that a bound function calling itself recursively could blow up the stack?

The definition of [[Call]] on bound function objects omits PrepareForTailCall() . Does this mean that bound functions do not support proper tail calls, and that a bound function calling itself recursively could blow up the stack?

No. The PrepareForTailCall happens in EvaluateDirectCall during the evaluation of the call expression , where it checks whether that expression is in a tail position. When the tail call is prepared, the current running execution context is dropped, before the function is called , dispatching on the respective [[Call]] internal method. The new running execution context is set up in PrepareForOrdinaryCall from the [[Call]] method of user-defined functions . The [[Call]] method of bound functions just introduces an extra level of indirection before that happens.

In the ECMAScript 2015 Language Specification, the definitions of Function.prototype.apply and Function.prototype.call both include " Perform PrepareForTailCall() " as one of their steps, so we know that these functions support proper tail calls.

Yes, this is necessary because the [[Call]] method of built-in functions sets up a new running execution context (for the "implementation-defined steps"). It is this "builtin context" that the PrepareForTailCall will drop before the actual function is called.

The call and apply methods are functions calling functions, and when they are called there are two calls on the stack that need to be tail-call-optimised. (Contrast this to - for example - Array.prototype.map , which also calls other functions, but here the map execution context stays on the call stack. In call and apply , the Call() is indeed in a tail position of the algorithm).

See §12.3.4.1 ( Runtime Semantics: Evaluation ). First, we do IsInTailPosition , then we do EvaluateDirectCall -- the result of which is F.[[Call]] . In other words, by the time we make the actual call, we already know whether or not we're in a tail position.

However, as you mention, JS is not tail-optimized on any browser , except Safari.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM