函数的递归调用
递归,就是函数内部自己调用自己,首先要把它想成函数的调用,如果一个函数递归调用了(自己调用了自己)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) 后面并没有执行语句,所以整个程序结束。再画一张图
函数纵然是自己调用自己,但每一次的调用都是一个全新的函数, 栈中为这个函数调用开辟的空间中保存着这个函数调用的完整信息,这个函数没有执行完之前,这些信息永远都会存在,也就是函数返回时,它依然能够获取调用时的信息。
原文地址:https://www.cnblogs.com/SamWeb/p/14670769.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 数据库PostrageSQL-启动数据库服务器
- 数据库PostrageSQL-PostgreSQL用户账户创建一个数据库集簇
- 轻松上手SpringBoot Security + JWT Hello World示例
- [Go] Golang发送http GET请求
- Windows系统快速安装Superset 0.37
- 商业数据分析从入门到入职(3)Excel进阶应用
- python列表练习
- python元组
- python字典、集合
- 秒懂JVM的三大参数类型,就靠这十个小实验了
- Netty之旅三:Netty服务端启动源码分析,一梭子带走!
- Mysql几种join连接算法
- Flutter 学习笔记 16 - Hero 动画
- sdk冲突记录
- 个人账号密码管理体系(密码篇)