JavaScript
的递归遍历会常常遇到,适当的运用递归遍历,能够提升代码性质量。javascript
咱们先看一下下面2个例子。前端
var arrList = [1,2,3,5,100,500,10000,10000,1000,10000002] //for循环测试 function forTest(){ console.time("for循环") for(let i in arrList){ console.log(((arrList[i] + arrList[i]) * 5 - arrList[i])/arrList[i]) } console.timeEnd("for循环") } //递归遍历测试 function recursive() { console.time("递归遍历") const testFun = function (i) { console.log(((arrList[i] + arrList[i]) * 5 - arrList[i])/arrList[i]) if(i == arrList.length - 1){ return } i++ testFun(i) } testFun(0) console.timeEnd("递归遍历") } forTest() recursive()
运行结果:vue
能够看到,for循环去遍历一个数组和用递归遍历去遍历同一个数组获得的结果同样,耗时也几乎相同。可是写法上有很大区别。
每一个递归都有一个结束递归的条件,上例中的:if(i == arrList.length - 1){ return }
。每个递归都会在函数内部把函数自己调用一次,可是函数在每次运行的时候,都会发生一些变化,用来触发递归的结束,上例中,testFun
函数在内部调用了本身,而且每次调用i
的值会+1,最终触发告终束条件,让递归结束。java
咱们先看下面的代码:git
var data = [ { name: "全部物品", children: [ { name: "水果", children: [{name: "苹果", children: [{name: '青苹果'}, {name: '红苹果'}]}] }, { name: '主食', children: [ {name: "米饭", children: [{name: '北方米饭'}, {name: '南方米饭'}]} ] }, { name: '生活用品', children: [ {name: "电脑类", children: [{name: '联想电脑'}, {name: '苹果电脑'}]}, {name: "工具类", children: [{name: "锄头"}, {name: "锤子"}]}, {name: "生活用品", children: [{name: "洗发水"}, {name: "沐浴露"}]} ] } ] }]
某些时候,坑逼后台让咱们遍历上面的一个数组,最后在页面上显示每一级的最后一个数据。就是下面的数据:es6
青苹果;红苹果;北方米饭;南方米饭;联想电脑;苹果电脑;锄头;锤子;洗发水;沐浴露;
咱们先用遍历的方式来实现:github
//普通遍历实现 var forFunction = function () { var str = "" data.forEach(function(row){ row.children.forEach(function(row){ row.children.forEach(function(row){ row.children.forEach(function(row){ str += (row.name + ";") }) }) }) }) console.log(str) } forFunction() //输出:青苹果;红苹果;北方米饭;南方米饭;联想电脑;苹果电脑;锄头;锤子;洗发水;沐浴露;
能够看到,前端累死累死写了4个forEach
实现了产品要的效果,这时候若是再加点别的什么逻辑,就很难弄了。这时候咱们尝试用递归的思想实现:数组
//递归遍历实现 var recursiveFunction = function(){ var str = '' const getStr = function(list){ list.forEach(function(row){ if(row.children){ getStr(row.children) }else { str += row.name + ";" } }) } getStr(data) console.log(str) } recursiveFunction() //输出:青苹果;红苹果;北方米饭;南方米饭;联想电脑;苹果电脑;锄头;锤子;洗发水;沐浴露;
能够看到,递归的方式来实现的时候,咱们只须要一个for循环,每次遍历接受到的数据,经过判断是否还有children
,没有就表明是最后一级了,有就继续把children
这个list
传给函数继续遍历,最后就获得了咱们想要的数据。异步
很明显,forEach
的遍历的方式能实现多级的遍历,而且数据格式能够灵活一些,可是遍历的层级有限,并且对于未知层级的状况下,就无从下手了。
递归遍历,理论上,只要内存够用,你能实现任意层级的遍历,但缺点也很明显,没一个层级里面须要有固定的数据格式,不然没法遍历。
咱们先看一下下面的需求,须要依次输出1,2,3,4,5
,每一个输出中间间隔1s
。
咱们先尝试下面的方式:函数
//常规实现 var forTest = function () { console.time("for时间") for (let i = 0; i < 5; i++) { setTimeout(function () { console.log('for循环输出:' + (i + 1)) if(i+ 1 === 5){ console.timeEnd("for时间") } }, 1000 * (i + 1)) } } forTest() //每隔一秒输出了1,2,3,4,5
上面咱们用let
当前做用域的特色实现了每隔1s输出,其实能够看出,是一块儿执行的,可是因为间隔时间不同,致使结果是每隔一秒输出的。
咱们再用递归的方式实现:
//递归遍历实现 var recursiveTest = function(){ console.time("递归时间") const test = function (i) { setTimeout(function () { i = i + 1 console.log('递归输出:' + i) if(i < 5){ test(i) }else { console.timeEnd("递归时间") } }, 1000) } test(0) } recursiveTest() //每隔一秒输出1,2,3,4,5
这里利用递归实现就很好理解了,在setTimeout
里面输出了以后,再开始下一个1s的输出。
最后咱们看一下运行截图:
经过截图上的耗时来看:递归遍历须要的时间更长,可是更好理解一下,并且不依赖es6的环境。
var quickSort = function(arr) { if (arr.length <= 1) {//若是数组长度小于等于1无需判断直接返回便可 return arr; } var pivotIndex = Math.floor(arr.length / 2);//取基准点 var pivot = arr.splice(pivotIndex, 1)[0];//取基准点的值,splice(index,1)函数能够返回数组中被删除的那个数 var left = [];//存放比基准点小的数组 var right = [];//存放比基准点大的数组 for (var i = 0; i < arr.length; i++){ //遍历数组,进行判断分配 if (arr[i] < pivot) { left.push(arr[i]);//比基准点小的放在左边数组 } else { right.push(arr[i]);//比基准点大的放在右边数组 } } //递归执行以上操做,对左右两个数组进行操做,直到数组长度为<=1; return quickSort(left).concat([pivot], quickSort(right)); }; var arr = [14, 50, 80, 7, 2, 2, 11]; console.log(quickSort(arr));
这是利用递归实现的快速排序,效率很高,有兴趣的同窗能够试试普通的遍历实现,再进行比较。
线上体验地址
全部的源码均可以在个人仓库地址:下载
我的博客:访问
学习如逆水行舟,不进则退,前端技术飞速发展,若是天天不坚持学习,就会跟不上,我会陪着你们,天天坚持推送博文,跟你们一同进步,但愿你们能关注我,第一时间收到最新文章。
我的公众号: