编程技巧:什么是JavaScript递归

什么是递归

程序调用自身的编程技巧称为递归(recursion)

递归的基本思想是将一个复杂的问题分解成更小、更易于管理的子问题,这些子问题与原始问题相似,但规模更小。

递归的要素

  • 基本情况(Base Case):
    这是递归终止的条件,也就是说,当问题足够小,可以直接解决而不需要进一步递归时,就会返回一个直接的答案。
  • 递归步骤(Recursive Step):
    在这一步中,问题被分解成更小的子问题,并且递归地解决这些子问题。每个递归调用都向基本情况更进一步。

递归与循环的比较

递归和循环是实现重复操作的两种基本方法。它们在不同的场景下各有优势。

场景

  • 递归适合解决可以分解为逐渐缩小的子问题的问题。
  • 循环通常用于需要重复执行固定次数的操作,或者在满足特定条件之前重复执行。

性能

  • 递归由于每次调用都会占用新的栈空间,可能会导致栈溢出,特别是在深度递归时。此外,递归的执行效率通常低于循环,因为它涉及更多的函数调用开销。
  • 循环通常更高效,因为它避免了函数调用的开销,并且可以更直接地控制循环的次数。

限制

  • 递归需要有明确的终止条件,否则会导致无限递归。
  • 循环也需要有明确的终止条件,否则也可能导致无限循环。

阶乘

递归实现阶乘:

基本情况:
基本情况就是结束条件,这可以有很多,比如:
n = 1 时,返回 1

n = 2 时,返回 2 (1 * 2

n = 3 时,返回 6 (1 * 2 * 3

我们使用最简单的结束条件:
n = 1 时,返回 1

递归步骤:
每次递归调用时,都会将之前的结果乘以当前数字,然后返回结果。

实现:

function factorial(n) {if (n == 1) return n;return n * factorial(n - 1);
}console.log(factorial(5)); // 5 * 4 * 3 * 2 * 1 = 120

通过下图,可以看出这个递归函数的实现原理:

循环实现阶乘:

function factorial(n) {let result = 1; for (let i = 2; i <= n; i++) {result *= i;}return result;
}console.log(factorial(5)); // 输出: 120

斐波那契数列

斐波那契数列是一个特殊的数列,其中每个数都是前两个数的和。

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

下来我们实现一个函数,返回斐波那契数列的第 n 个数。

斐波那契数列的递归实现:

基本情况:

如果 n 为 0 或 1 ,直接返回 n

递归步骤:

每次递归调用都返回前两个数的和。

实现:

function fibonacci(n) {if (n === 0) return 0;if (n === 1) return 1;return fibonacci(n - 1) + fibonacci(n - 2);
}// 计算第6项斐波那契数
console.log(fibonacci(6)); // 输出: 8

斐波那契数列的循环实现:

function fibonacci(n) {// 初始化数组,包含前两项let fib = [1, 1];for (let i = 2; i < n; i++) {// 计算当前项,即前两项的和fib[i] = fib[i - 1] + fib[i - 2];}return fib[n - 1];
}// 计算第6项斐波那契数
console.log(fibonacci(6)); // 输出: 8

尾递归

我们看这个斐波那契数列的递归实现,他的函数调用次数要比循环次数多很多。我们打印出来看下。

let count = 0;
function fibonacci(n) {count++;if (n === 0) return 0;if (n === 1) return 1;return fibonacci(n - 1) + fibonacci(n - 2);
}// 计算第6项斐波那契数
console.log(fibonacci(6)); // 输出: 8
console.log(`调用 ${count} 次`); // 输出: 调用 25 次

函数执行一次,就会创建一个执行上下文,并且压入执行上下文栈,当函数执行完毕的时候,就会将函数的执行上下文从栈中弹出。我们这个递归函数,创建很多执行上下文压入执行上下文栈。

递归次数过多还会导致栈溢出。

在 chrome 浏览器的 Sources 面板中,我们通过 Call Stack 可以看到执行上下文的函数调用栈的具体情况

下来我们开始使用尾递归优化这个递归函数。

尾递归是指递归函数内部的最后一个动作是函数调用。该调用的返回值,直接返回给函数。
这样就可以避免创建新的栈帧。

我们直接将上一次的结果,作为参数传递给下一次的函数调用。

function fibonacci(n, ac1 = 1, ac2 = 1) {if (n == 1 || n == 2) {return ac2;}return fibonacci(n - 1, ac2, ac1 + ac2);
}// 计算第6项斐波那契数
console.log(fibonacci(6)); // 输出: 8

注意:
上面的 fibonacci 函数虽然已经使用了尾递归优化,但还是可能出现栈溢出。

因为 JavaScript 引擎并不总是能够优化尾递归调用以避免栈溢出。这是因为尾递归优化( Tail Call Optimization , TCO )并不是 JavaScript 语言规范的一部分,也不是所有 JavaScript 引擎都实现了这一优化。

在没有 TCO 的环境中,每次递归调用仍然会占用新的栈空间,fibonacci 函数的每次调用都需要保留其执行上下文(包括参数和局部变量),直到该调用的返回值被使用。随着 n 的增加,递归调用的深度也会增加,这最终可能导致栈溢出。

递归应用的业务场景

数组转树

比如在做权限控制、级联选择组件的时候,后端返回的数据可能是数组,前端需要将其转换为树形结构。这时可以使用递归来解决。

JavaScript 实现扁平数组与树结构的相互转换

递归组件

在 Vue 中,递归组件是一种可以调用自身作为其子组件的组件。递归组件非常适合用来展示嵌套的或者树状的数据结构,例如文件系统、组织结构图、菜单列表等。

在做侧边栏可能有多个层级的时候,可以使用递归组件。

在 vue-element-admin 项目中的 SidebarItem 组件 就是使用了递归组件。

总结

使用递归解决问题,重点是如果把问题分解为更小的相同问题,确定递归终止条件,然后递归调用自身。使用递归要注意栈溢出问题,可以考虑使用尾递归优化。

前端的世界总是在不断变化,作为开发者,我们需要保持好奇心和学习热情,不断探索新的技术,只有这样,我们才能在这个快速发展的时代中立于不败之地。介绍一款程序员都应该知道的软件JNPF快速开发平台平台非常好用,是功能的集大成者,任何信息化系统都可以基于它开发出来。

这是一个基于 Java Boot/.Net Core 构建的简单、跨平台快速开发框架。前后端封装了上千个常用类,方便扩展;集成了代码生成器,支持前后端业务代码生成,实现快速开发,提升工作效率;框架集成了表单、报表、图表、大屏等各种常用的 Demo 方便直接使用;后端框架支持 Vue2、Vue3。如果你有闲暇时间,可以做个知识拓展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/836600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 编程语言中的 None 到底是什么?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 让我们一起深入了解 Python 中的 None。 什么是 None&#xff1f; 在 Python 编程语言中&#xff0c;None 是一个特殊的常量&#xff0c;它代表了 “无” 或 “没有值”。你可以把它想象成一个空盒子…

Debian常用命令:高效管理与运维的必备指南

在Linux世界中&#xff0c;Debian以其稳定性、安全性和开源精神赢得了广大用户的青睐。作为一个基于Linux的操作系统&#xff0c;Debian拥有丰富且强大的命令行工具&#xff0c;这些命令对于系统管理员和开发者来说至关重要。本文将为您介绍一系列Debian系统中的常用命令&#…

python 自定义包的实现

1. 代码目录 创建自定义包的时候&#xff0c;原理是当 python 检测到一个目录下存在 __init__.py 文件时&#xff0c;python 就会把它当成一个模块(module)。 下面这个例子是网上整理的代码&#xff0c;但是有些小改动&#xff0c;可以直接拿来就用。 看代码结构&#xff1a;…

flink尚硅谷

flink 1 flink基础使用1.1 角色1.2 部署模式&#xff08;抽象&#xff09;1.2.1 会话模式1.2.2 单作业模式1.2.3 应用模式 1.3 运行模式&#xff08;实际 谁来管理资源&#xff09;1.3.1 Stand alone1.3.2 YARN运行模式&#xff08;重点&#xff09; 2. 运行时架构2.1 系统架构…

【Java EE】网络原理——TCP1

目录 1.TCP协议格式 2.TCP协议的特点 3.TCP协议的核心机制&#xff08;十个&#xff09; 3.1确认应答机制 3.2超时重传 3.3连接管理 3.3.1三次握手基本流程&#xff1a; 3.3.2三次握手的意义或者解决的问题&#xff1a;&#xff08;面试题&#xff09; 3.3.3三次握手时…

什么是无人直播?无人直播软件带你探索全新的赚钱模式!

在当今数字化时代&#xff0c;AI技术的迅猛发展正引领着各行各业的深刻变革。其中&#xff0c;AI实景自动无人直播软件以其独特的优势&#xff0c;正成为商家们提升品牌形象、扩大市场影响力的重要工具。本文将详细介绍这款软件的功能特点及其在商业领域的应用价值。全网最新智…

RabbitMQ中间件安装

消息队列 RabbitMQ yum -y update yum -y install epel-release erlang # 安装erlang erl -version # 判断是否安装成功根据官网的的表格判断自己用哪个版本的 RabbitMQ&#xff1a;https://www.rabbitmq.com/docs/which-erlang#r16b03 [rootiZuf6hqrs5cb2ccyuc9nqvZ ~]# er…

【C++历练之路】unordered_map与unordered_set的封装实现

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 前言&#xff1a;我们已经认识并实现了哈希底层的逻辑&#xff0c;创建出了其开散列。现在我们要进行封装&#xff0c;类比STL中的unordered_set 与 unordered_map。 目录 1. 模拟实现 1.1 哈希表的改造 1.2 unorde…

uabntu pcl spdlog安装位置和版本查看那

查看pcl默认安装版本 pkg-config --modversion pcl_io 查看pcl路径 pkg-config --libs pcl_io

企业计算机服务器中了rmallox勒索病毒怎么破解,rmallox勒索病毒解密工具步骤

科技技术的发展&#xff0c;为企业的生产运营注入了新的活力&#xff0c;越来越多的企业利用网络走向了数字化办公模式&#xff0c;网络也极大地方便了企业的生产运营&#xff0c;大大提高了企业的生产效率&#xff0c;加快了企业发展的步伐。但是网络数据安全问题一直是企业关…

Swift 集合类型

集合类型 一、集合的可变性二、数组&#xff08;Arrays&#xff09;1、数组的简单语法2、创建一个空数组3、创建一个带有默认值的数组4、通过两个数组相加创建一个数组5、用数组字面量构造数组6、访问和修改数组7、数组的遍历 三、集合&#xff08;Sets&#xff09;1、集合类型…

某攻防演练心得之随笔记

最近太忙了&#xff0c;忙于各种奇奇怪怪的事情&#xff0c;有攻防&#xff0c;有应急&#xff0c;有渗透&#xff0c;还成为了一段时间内的“word高级工程师”......有师傅说我现在更新的越来越慢了&#xff0c;是呀&#xff0c;其实我也不知道怎么了&#xff0c;每天各种新闻…

科林Linux_4 信号

#include <signal.h> 信号signal&#xff1a;Linux或Unix系统支持的经典的消息机制&#xff0c;用于处置进程&#xff0c;挂起进程或杀死进程 kill -l #查看系统支持的信号 1~31 Unix经典信号&#xff08;软件开发工程师&#xff09; 32、33信号被系统隐藏&#xf…

加入全球少儿编程运动:Scratch让每个孩子都能成为创造者(Scratch最新版客户端和初/中/高级学习资料整理分享)

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f3e1; 演示环境 &#x1f3e1;&#x1f4d2; 文章内容 &#x1f4d2;&#x1f4dd; 安装与使用&#x1f4dd; 社区与资源 &#x1f388; 获取方式 &#x1f388;⚓️ 相关链接 ⚓️ &#x1f4d6; 介绍 &#x1f4d6; 你知道…

【Linux】- Linux环境变量[8]

目录 环境变量 $符号 自行设置环境变量 环境变量 环境变量是操作系统&#xff08;Windows、Linux、Mac&#xff09;在运行的时候&#xff0c;记录的一些关键性信息&#xff0c;用以辅助系统运行。在Linux系统中执行&#xff1a;env命令即可查看当前系统中记录的环境变量。 …

升级你的网络实验场:体验华为最新ENSP_PRO模拟器,现已对普通用户开放!

随着网络技术的不断发展&#xff0c;网络实验场的重要性越来越凸显。在这个数字化时代&#xff0c;网络工程师和学习者需要一个高效、全面的模拟器来进行网络实验和测试。最新消息称&#xff0c;华为已将其最新的ENSP_PRO模拟器对普通用户开放&#xff0c;为广大网络爱好者和专…

VScode查看以十六进制查看文件的插件说明

找到插件并下载 打开指定的文件 选择打开方式即可 结果如下

C++/Qt 小知识记录6

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识6 dumpbin工具查看库导出符号OSGEarth使用编出的protobuf库&#xff0c;报错问题解决VS2022使用cpl模板后&#xff0c;提示会乱码的修改设置QProcess调用cmd.exe执行脚本QPainterPath对线段描边处理…

英文文本标点恢复

文章目录 一、安装 rpunct二、使用三、下载模型时报错1、报错详情2、报错原因3、解决方案 四、程序运行时报错1、报错详情2、报错原因3、解决方案 五、修改默认缓存路径 一、安装 rpunct pip install rpunct 相关依赖包信息&#xff1a; langdetect1.0.9 pandas1.2.4 simpletr…

Java入门最小必要知识:变量及其本质

编程语言是与计算机交流的桥梁&#xff0c;而在编程世界中&#xff0c;变量是这座桥上不可或缺的砖石。 从本质上&#xff0c;可以把复杂的编程工作简化为两件事&#xff1a; ①定义变量②操作变量 可见&#xff0c;变量之于编程的重要性。 对于Java开发者&#xff0c;理解…