• 函数的递归调用


      递归,就是函数内部自己调用自己,首先要把它想成函数的调用,如果一个函数递归调用了(自己调用了自己)5次,可以把它想成5个函数的调用,fn1 调用fn2(), fn2调用fn3(), fn3调用了fn4(), fn4调用了fn5(), 只不过fn1, fn2, fn3, fn4, fn5 都是一样的函数。函数的每一次调用,都会栈中开辟一块空间,保存着这个函数调用的所有信息,比如传递过来的参数,如果该函数没有执行完,这些信息是不会释放的。fn1调用fn2() , 如果fn2()没有完成,并返回到fn1,fn1的空间永远都不会释放,它里面的保存的信息会一直存在。同理,fn2 调用了fn3(), 如果fn3没有执行完,fn2的空间也就不会释放。 正是由于函数不停地调用,不停地分配内存空间,总有一个函数要返回,不会再调用函数,否则内存就使用完了。对于递归来说,就是函数不会再调用自己了,这也就是说,递归函数的内部肯定存在一个条件,当达到这个条件的时候,函数不会调用函数(自己)。函数的返回是返回到调用它的函数的地方,fn5执行完了,永远都是返回到fn4, fn4在执行的时候,是从调用fn5() 的地方开始向下继续执行,  相当于在 fn4中,调用函数结束了,开始执行调用函数语句下面的语句。当一个函数调用另一个函数的时候,被调用的函数永远都是从函数第一行语句开始执行。

      简单写一个打印函数理解一下

    function upAndDown(n) {
        console.log("before call " + n);
        if (n < 3) {
            upAndDown(n + 1);
        }
        console.log("after call " + n);
    }
    
    upAndDown(1)
    

      程序执行时,调用upAndDown(1), 函数接受到参数1,开始执行,把这次调用看做是fn2, 输出了 "before call 1",  if 判断(1< 3)成立,函数调用自己,看做一次普通的函数调用就可以了,就叫fn3吧,fn2 调用了fn3,把参数2传递过来,函数fn3开始执行,函数执行永远都是从函数第一行语句开始执行,它输出了"before call 2"。 这里要注意的是函数fn2并没有执行完, 它还等着fn3的返回,并执行后面的console.log语句,所以n =1 是会保存起来的。函数fn3() 继续执行,还是if 判断(2 < 3) 成立,继续调用自己,生成了一次函数的调用fn4,并把参数3,传递过去,此时,fn3 也没有执行完成,它在等待fn4 的执行结果。f4 接受到参数3,开始执行,输出"before call 3",进行if 判断,由于3 < 3 不成立,if代码块不会执行,函数终于不用再继续调用自己了,同时,函数也有机会执行到if 后面的语句了,输出"after call 3", 由于console.log() 后面没有语句了,函数执行完毕,fn4调用完了,它会返回到调用它的fn3 函数,fn3 终于有机会执行了,它会继续执行函数调用语句后面的语句,也就是console.log("after call " + n), 由于fn3 的空间中保存着n的信息,那就是2, 所以输出了"after call 2"。 fn3 执行完,返回到fn2, fn2 同样是输出 "after call 1" ,  然后返回,主程序中upAndDown(1) 后面并没有执行语句,所以整个程序结束。再画一张图

      函数纵然是自己调用自己,但每一次的调用都是一个全新的函数, 栈中为这个函数调用开辟的空间中保存着这个函数调用的完整信息,这个函数没有执行完之前,这些信息永远都会存在,也就是函数返回时,它依然能够获取调用时的信息。  

  • 相关阅读:
    在MS Sql Server中可以能过以下的方法查询出磁盘空间的使用情况及各数据库数据文件及日志文件的大小及使用利用率:
    sqlserver日志的备份与还原
    C#中String 与Color之间的相互转换
    sql 替换字符串
    Components_Box
    射线检测与碰撞通道设置
    切碎方块
    音乐可视化
    枚举
    UI与Actor(蓝图)的互动
  • 原文地址:https://www.cnblogs.com/SamWeb/p/14670769.html
Copyright © 2020-2023  润新知