递归函数是函数自身调用自身,必须有明确终止条件以防栈溢出;其结构包含基础情况(停止条件)和递归情况(缩小问题规模并再调用);需避免修改全局状态、确保参数趋近基础情况,并可加深度限制或改用迭代优化。

递归函数就是函数自己调用自己,关键在于必须有明确的终止条件,否则会无限调用导致栈溢出(Maximum call stack size exceeded)。
递归的基本结构
一个安全的递归函数包含两个核心部分:基础情况(base case)和递归情况(recursive case)。基础情况是停止递归的条件,递归情况负责缩小问题规模并再次调用自身。
- 基础情况必须能被最终触发,且不依赖递归调用
- 每次递归调用的参数要更接近基础情况,比如数值变小、数组变短、对象层级变浅
- 避免在递归中修改全局状态或共享引用,容易引发逻辑混乱
常见终止条件写法
终止条件通常基于输入值的边界判断,不同场景写法不同:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 数值类(如阶乘、斐波那契):
if (n - 数组/字符串遍历:
if (arr.length === 0) return;或if (index >= arr.length) return; - 树结构遍历:
if (!node) return;或if (node.left === null && node.right === null) return; - 深度限制防护(额外保险):
if (depth > MAX_DEPTH) throw new Error("Too deep");
防止栈溢出的实用技巧
JavaScript引擎对调用栈深度有限制(通常几千层),除了写好终止条件,还可主动降低风险:
- 优先考虑迭代替代深层递归,比如用 while 循环+栈模拟DFS
- 对已知可能很深的数据(如超长链表、深层嵌套对象),加最大递归深度计数器
- 尾递归优化(ES6支持但仅限严格模式且需特定写法),例如把计算积累到参数中:
function sum(n, acc = 0) { return n (注意:V8等引擎不一定实际优化) - 异步拆分(适用于非实时场景):用
setTimeout或Promise.resolve().then()把递归“切片”,释放调用栈
一个安全的递归示例:扁平化嵌套数组
这个例子包含清晰终止条件、参数收敛、深度防护:
function flatten(arr, depth = Infinity, currentDepth = 0) {
if (!Array.isArray(arr)) return [arr];
if (currentDepth > depth) return arr; // 深度限制
if (arr.length === 0) return []; // 基础情况
<p>return arr.reduce((acc, item) => {
if (Array.isArray(item) && currentDepth </p><p>调用 <code>flatten([1, [2, [3, [4]]]], 2)</code> 不会无限深入,也避免了默认无限嵌套导致的栈溢出。</p>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










