前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS编程: 递归

JS编程: 递归

作者头像
疯狂的技术宅
发布2019-03-28 10:45:19
2.6K0
发布2019-03-28 10:45:19
举报
文章被收录于专栏:京程一灯京程一灯

想成为一个更好的开发者,那么理解数据结构、算法和基本编程思想是必须的。现在大多数问题都被现代工具和各种库解决了,但是对这些领域有一个更深的了解,将会大大拓宽你软件开发的视野。

就我自己而言,掌握这些概念是相当困难的,因为在我每天的工作里,几乎都不用这些。我正在写的这一系列文章就是为了提升我和那些跟我一样的人对这些方面的理解。

什么是递归

递归是主要的编程思想之一。毫无疑问,你已经在一些算法书籍和文章里,以及计算斐波纳契数列或者相似内容的例子里,看到了一些可怕的词汇。但作为一个网页开发人员,在你的日常编码工作或者实现排序算法时,可能并没有用到斐波纳契数列,至少我没有。

当我第一次开始阅读关于递归时,在理解哪里能被正确的使用时遇到了问题。我知道这个方法的好处以及在某些特定算法里的用途,但是很难找到更应该使用递归而不是迭代的场景。

在继续之前——本文希望你对递归和JavaScript有一个基本的了解。所以,让我们从一个我觉得容易理解的定义开始:

递归就是一个函数调用自身,直到达到某个特定状态。

让我们把它分为两部分,然后分别讨论。一个调用自身的函数意思是在函数体内,我们将调用同一个函数——初始化(inception),对吗?你第一次看见一个递归函数的时候,可能会打破你对函数执行的理解,但它绝对是正常的。

当我们使用递归,它会一直持续到到达某一特定状态为止。在某些情况下,我们调用函数必须是固定次数。但在其它情况下,它会持续运行,直到一个条件检查告诉它停下。这两种情况,我们都必须有一个明确的停止条件,以防止递归一直执行。

应用递归

定义和解释并不能让我们实现什么,所以让我们从一个实际的例子开始。我们将使用递归来说明怎样把一个分类列表排序成树状机构。这里是我们从服务端获取到的分类,它们包含了自己的名字和父类:

代码语言:javascript
复制
const categories = [
 { name: 'tech', parent: null },
 { name: 'hot_right_now', parent: 'tech' },
 { name: 'upcomming_releases', parent: 'tech' },
 { name: 'gadgets', parent: 'tech' },
 { name: 'news', parent: null },
 { name: 'social', parent: 'startups' },
 { name: 'europe', parent: 'news' },
 { name: 'asia', parent: 'news' },
 { name: 'events', parent: 'news' },
 { name: 'startups', parent: null },
 { name: 'funding', parent: 'startups' },
 { name: 'unicorns', parent: 'startups' },
 { name: 'venture_capital', parent: 'funding' },
 { name: 'crowdfunding', parent: 'funding' },
 { name: 'usa', parent: 'news' }
 ]

作为一个JavaScript开发人员,你的任务是把这些类排列为一个树状结构,以便展现在页面的某些地方。首先你能想到的是使用一些循环嵌套,然而这并不是一个优雅的方法。它暂时是可以正常工作的,但是这取决于列表结构以后都不变。如果某个时刻子节点删除或者增加,你将不得不修改你的代码。

这是一个说明什么时候使用递归比普通的迭代方法更好的完美示例。我们会从创建一个函数开始,它包含两个参数——一个数组和一个我们正在查询的类的父类。请记住,我们不仅仅是从全局接收类,因为我们将会递归地传入这些类。

代码语言:javascript
复制
const arrangeCategories = (category, parent) => {
  let result = {}
  // function body here
  return result
}

递归主体

接下来,我们需要正真的实现递归。我们的目标是得到一个不需要依赖嵌套层级的算法。这里是一个我们将要使用的完整函数:

代码语言:javascript
复制
const arrangeCategories = (categories, parent = null) => {
   let result = {}
   categories
     .filter(category => category.parent === parent)
     .forEach(category => {
       result[category.name] = arrangeCategories(categories, category.name)
     })
   return result
 }

让我们看看这都发生了什么。

  1. 在第4行,我们过滤类别,只得到正确的父项(在第一次调用时为空)
  2. 在我们拿到所需的类别后,遍历每一个我们作为结果对象的键所添加的类,并且递归调用,找到它的所有子类。
  3. 重复第一步

结果

在使用递归函数后,我们得到以下结果:

代码语言:javascript
复制
{
   "tech": {
     "hot_right_now": {},
     "upcomming_releases": {},
     "gadgets": {}
   },
   "news": {
     "europe": {},
     "asia": {},
     "events": {},
     "usa": {}
   },
   "startups": {
     "social": {},
     "funding": {
       "venture_capital": {},
       "crowdfunding": {}
     },
     "unicorns": {}
   }
 }

所有类别都经过排序,创建出一个更恰当的层级结构,以便更容易循环和展示。递归绝对是一个宽泛的话题,用它来解决问题比简单地列出未排序的分类要难的多,但这是一个不错的开始。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是递归
  • 应用递归
  • 递归主体
  • 结果
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档