递归(Recursion)快速上手指南【JS例子】

目录

递归是什么?

递归是一种 函数自己调用自己 的编程方式,用来解决 复杂但结构重复 的问题。

什么时候使用递归?

当问题能被拆成 与原问题结构相同但更小的子问题 时,就可以使用递归。

场景 示例
处理树形结构 菜单树、组织树、文件夹结构
链式结构 链表、路径寻找
重复计算 斐波那契、阶乘
深度遍历 DFS、查找嵌套结构
分治算法 快排、归并

递归的核心要素

要素 说明
🔹 终止条件 必须有,避免无限循环
🔹 递归调用 函数自己调用自己,处理子问题
🔹 返回结果 每层递归如何返回和组合结果

模版写法

javascript 复制代码
function recursion(data) {
  // 1. 终止条件(必须有!)
  if (满足结束条件) return 结果;

  // 2. 递归调用
  return recursion(缩小后的数据);
}

从简单到复杂的递归案例

求阶乘

javascript 复制代码
function factorial(n) {
  if (n === 1) return 1;  // 终止条件
  return n * factorial(n - 1);  // 递归调用
}

console.log(factorial(5)); // 120

斐波那契数列(有重复计算)

javascript 复制代码
function fib(n) {
  if (n <= 1) return n; // 终止条件
  return fib(n-1) + fib(n-2); // 递归调用
}
console.log(fib(6)); // 8

斐波那契数列是什么?

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

从第三个数开始,每个数 = 前两个数相加。也就是:第0项:0,第1项:1,第2项 = 0 + 1 = 1,第3项 = 1 + 1 = 2,第4项 = 1 + 2 = 3,第5项 = 2 + 3 = 5,第6项 = 3 + 5 = 8

斐波那契数列的数学公式

javascript 复制代码
F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2)

数组求和

javascript 复制代码
function sumArray(arr) {
  if (arr.length === 0) return 0;
  return arr[0] + sumArray(arr.slice(1));
}
console.log(sumArray([1,2,3,4])); // 10

扁平化多维数组

javascript 复制代码
function flatten(arr) {
  let res = [];
  for (const item of arr) {
    if (Array.isArray(item)) {
      res = res.concat(flatten(item)); // 递归展开
    } else {
      res.push(item);
    }
  }
  return res;
}

console.log(flatten([1, [2, [3, [4]], 5]]));  

查找树形结构节点

javascript 复制代码
function findNode(tree, id) {
  for (const node of tree) {
    if (node.id === id) return node; // 终止条件
    if (node.children) {
      const found = findNode(node.children, id); // 递归调用
      if (found) return found;
    }
  }
  return null;
}

树结构映射(渲染前端菜单/组件树)

javascript 复制代码
function mapTree(nodes) {
  if (!nodes || nodes.length === 0) return [];
  return nodes.map(node => ({
    label: node.name,
    value: node.id,
    children: mapTree(node.children) // 递归处理子节点
  }));
}

深度遍历 DOM 节点

javascript 复制代码
function traverseDOM(node) {
  console.log(node.tagName);
  node.childNodes.forEach(child => traverseDOM(child));
}
traverseDOM(document.body);

查找嵌套评论(评论树展开)

javascript 复制代码
function collectComments(comments) {
  let result = [];
  comments.forEach(c => {
    result.push(c.text);
    if (c.replies) {
      result = result.concat(collectComments(c.replies));
    }
  });
  return result;
}

快速排序(分治递归)

javascript 复制代码
function quickSort(arr) {
  if (arr.length <= 1) return arr; // 终止条件
  const pivot = arr[0];
  const left = arr.slice(1).filter(x => x <= pivot);
  const right = arr.slice(1).filter(x => x > pivot);
  return [...quickSort(left), pivot, ...quickSort(right)];
}

计算对象嵌套属性数量

javascript 复制代码
function countKeys(obj) {
  let count = 0;
  for (const key in obj) {
    count++;
    if (typeof obj[key] === 'object' && obj[key] !== null) {
      count += countKeys(obj[key]); // 递归
    }
  }
  return count;
}

递归vs循环

场景 适合递归 适合循环
树结构
链表
数组遍历
深度搜索 DFS
性能敏感
可读性要求

树 = 递归优先;线性 = 循环优先

相关推荐
CCPC不拿奖不改名5 分钟前
网络与API:从HTTP协议视角理解网络分层原理+面试习题
开发语言·网络·python·网络协议·学习·http·面试
小王和八蛋13 分钟前
前端存储与离线应用实战:Cookie、LocalStorage、PWA 及 Service Worker 核心知识点
前端·javascript
代码游侠14 分钟前
学习笔记——HC-SR04 超声波测距传感器
开发语言·笔记·嵌入式硬件·学习
superman超哥26 分钟前
Context与任务上下文传递:Rust异步编程的信息高速公路
开发语言·rust·编程语言·context与任务上下文传递·rust异步编程
步达硬件27 分钟前
【Matlab】批量自定义图像处理
开发语言·matlab
军军君0129 分钟前
Three.js基础功能学习七:加载器与管理器
开发语言·前端·javascript·学习·3d·threejs·三维
哈__30 分钟前
React Native 鸿蒙开发:内置 Share 模块实现无配置社交分享
javascript·react native·react.js
liulilittle31 分钟前
OPENPPP2 网络驱动模式
开发语言·网络·c++·网络协议·信息与通信·通信
mjhcsp34 分钟前
C++ AC 自动机:原理、实现与应用全解析
java·开发语言·c++·ac 自动机
huihuihuanhuan.xin35 分钟前
后端八股之java并发编程
java·开发语言