js递归

90 阅读2分钟

js递归

说递归之前感觉有必要说一下函数的执行栈

  1. 任何代码的执行都必须有一个执行环境,执行环境为代码的执行提供支持。
  2. 执行环境是放到执行栈中的。
  3. 每个函数的调用,都需要创建一个函数的执行环境,函数调用结束,执行环境销毁。

用一段代码解释吧,这个代码最终会输出什么,答案是 1.global begein 2.A begin 3.B begin 4.C begin 5.C over 6.B over 7.A over 8.global over。 如果你的答案是对的,可能后面的你就不需要看了。

1721892820208.jpg

下面解释一下为啥会是这样的

  1. 执行代码创建全局环境,遇到 A B C 三个函数先不管,因为没有执行,接下来遇到 console.log("global begin")这是一个函数调用,放入执行栈中,执行完毕输出global begin后console.log出栈
  2. 遇到A(),函数A环境入栈,执行函数A,遇到console.log("A begin");入栈执行,输出A begin,此时A函数执行环境还在执行栈内,因为没有执行完。
  3. 遇到 B(),函数B环境入栈,执行函数B,遇到console.log("B begin");入栈执行,输出B begin;此时B函数执行环境还在执行栈内。
  4. 遇到C(),函数C环境入栈1721895065256.jpg
  5. 执行函数C,遇到console.log("C begin");入栈执行,输出C begin,遇到console.log("C over");入栈执行,输出C over;函数C执行完毕,出栈。
  6. 接下来继续执行函数B,输出B over,函数B出栈
  7. 继续执行函数A,输出A over,函数A出栈
  8. 继续执行全局环境,输出global over。执行栈清空,代码执行完毕。

接下来说递归,函数递归的概念很简单,就是 函数直接或间接调用自身。 举个经典的例子,求斐波拉契数列第n位的值

1721896031217.jpg 代码其实很简单,重点在于理解

  1. 先创建全局环境,遇到console.log(f(5));入栈执行,
  2. 遇到f(5),入栈执行,得出f(5)=f(4)+f(3);
  3. 遇到f(4),入栈执行,得出f(4)=f(3)+f(2);
  4. 遇到f(3),入栈执行,得出f(3)=f(2)+f(1);
  5. 遇到f(2),入栈执行,得出f(2)=1;继续执行f(3)函数,遇到f(1)=1,f(3)执行完毕,f(3)=2;
  6. 继续执行f(4)函数,遇到f(2),得出f(2)=1,f(4)=f(3)+f(2)=2+1=3;f(4)执行完毕;f(4)=3;
  7. 继续执行f(5)函数,遇到f(3),f(3)=f(2)+f(1)=1+1=2;f(3)执行完毕;至此f(5)执行完毕;f(5)=f(4)+f(3)=3+2=5
  8. 其实就是函数入栈出栈,一步步算出结果。入栈出栈图形没画,太麻烦了。

递归函数必须要有出口,如果没有出口会无线递归,会导致栈溢出,报Maximum call stack size exceeded,超过最大调用栈大小。 无线递归和死循环不一样,死循环不会报错,也不会导致栈溢出,但是浏览器会一直转圈,没反应