javascript Series - tail calls and tail recursion

  Recently read "Hu Yu's blog," say really, really benefit, have seen javascript in-depth series of articles and most of the Series, but now remembered to take notes. So although many interviews before being forced to rip off his face asked questions are "awoken" before, pay attention to where I said "too." Yes, these known points, then I look to follow when thinking big brother really was feeling "turned out to be oh so", but saw the next chapter of the knowledge forget or let me feel the setbacks too.
Thus, the decision to write a little note to deepen the impression of it!
  Today saw the "javascript topic of recursion" ( https://github.com/mqyqingfeng/Blog/issues/49 ) this, so we start here!
Here, I once again saw the tail calls and tail recursion maybe has a keyword, once seen as if still a lot of years ago before the distance, but was completely unknown so ah ..., but, today, before the combination the execution context and execution context stack knowledge, finally understand that in the end is Gesha up!
   Tail calls, refers to the last operation of a function is internal function call. The return value of the call, return directly to the function.
   Tail-recursive function calls itself recursively called. If the tail call itself, it is called tail recursion.
  As for why many scenes to promote the use of tail call, why use tail calls and tail recursion will have a better performance? It comes to the knowledge of the execution context stack. https://github.com/mqyqingfeng/Blog/issues/4 : when performing a function will create a execution context , and pressed into the execution context stack , when the function completes, execution of the function will be pop-up context from the stack. So my understanding is: precisely because of this execution context is ejected, freeing up memory, so performance has improved on it!
  Last call:
// tail call 
function F (X) {
     return G (X);
}

  note:

// non tail call 
function F (X) {
     return G (X) +. 1 ;
}
Because the g (x) need to keep a return value is calculated, f (x) returns a value.
Both just this little bit of difference + 1, What is the difference? The answer is to change the execution context stack is not the same.
In order to simulate the behavior of the execution context stack, let's define the execution context stack is an array:
ECStack = [];
Execution of tail calls:
// analog pseudocode: 
ECStack.push (<F> functionContext);
ECStack.pop();
ECStack.push(<g> functionContext);
ESStack.pop();
 
Execution of non-tail calls:
ECStack.push(<f> functionContext);
ECStack.push(<g> functionContext);
ECStack.pop();
ECStack.pop();
 
  It can be seen trailing tail calls and non-calls are required to call function f () and g () function, however, the end of call, when the call f (), immediately release the f () execution context, the implementation of g (), when it is left g () execution context, the first two are not the end call function has pushed on the execution stack context, executing the last function to be performed and only then pop the context of two functions ( before the end of the last function is not performed in front of the function execution context it has been dominated by memory ).
  Factorial function:
// non tail call wording: 
function factorial (n-) {
     IF (n-==. 1) return n-;
     return n-* factorial (n--. 1 );
}
factorial(5) // --> 5 * 4 * 3 * 2 * 1 = 120


// Last call optimization wording: 
function factorial (n-, RES) {
     IF (n-==. 1) return RES;
     return factorial (n--. 1, * n- RES)
}

 

 

Guess you like

Origin www.cnblogs.com/garfieldzhong/p/11932894.html