递归函数

1,989 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

大家好,我是大帅子,今天给大家讲一下递归吧, let′s go


1. 递归函数是啥

在函数的内部自己调用自己

2. 特点

与循环类似,一般开发中可以用循环解决的,递归也可以解决,就是写法不同而已

3. 单函数递归

自己调用自己

function fn(){
    console.log(1)
    // 递归调用
    fn()
}
fn()

4. 双函数递归

function fn (){
    console.log(1)
    fn1()
}

function fn1 (){
    console.log(8888) 
    fn ()
}
fn()

5. 一个简单的递归函数

例如我们要求1-5的和

   // 用循环求和
    let sum = 0
    for (let i = 0; i <= 5; i++) {
      sum += i
    };
    console.log(sum);
  // 用递归求和
    function getSum(num) {
      if (num == 1) {
        return 1
      } else if (num == 2) {
        return 2 + getSum(1)
      } else if (num == 3) {
        return 3 + getSum(2)
      } else if (num == 4) {
        return 4 + getSum(3)
      } else if (num == 5) {
        return 5 + getSum(4)
      }...
    }

    console.log(getSum(5));

这个时候肯定有的兄弟们就在想了,这是什么垃圾博主,三行的代码写了30行,别慌铁子们,我们学东西慢慢来嘛,我们可以发现除了上面的num==1的条件其他的条件似乎都是类似的,那我们就来精简一下

   function getSum(num) {
     if (num == 1) {
       return 1
     } else {
       return num + getSum(num-1)
     }
   }

   console.log(getSum(5));
   

打个断点看一下 image.png

6.应用场景

在我们实际的开发中,就是用来深拷贝的,实际我们用的递归拷贝并不多,用的多的我就给大家提一下

  let obj = {
      name: '张三',
      age: 18,
      hobby: ['唱', '跳', 'rap', '篮球'],
      eat: {
        name: '北京烤鸭',
        drink: '茶颜悦色'
      }
  }
  
   // 浅拷贝 复制的 对象改变原来的对象一样会跟着改变
    let obj1 = obj
    obj1.name = 'niu'
    console.log(obj, obj1)
    
    //深拷贝
    let obj1 = JSON.parse(JSON.stringify(obj))
    console.log(obj1 === obj)   //false 

递归

    // 用递归的做法
    function diGui(newObj, obj) {
      for (let key in obj) {
        if (obj[key] instanceof Array) {
          // 引用类型  数组
          newObj[key] = []
          diGui(newObj[key], obj[key])
        } else if (obj[key] instanceof Object) {
          // 引用类型  对象
          newObj[key] = {}
          diGui(newObj[key], obj[key])
        } else {
          //值类型
          newObj[key] = obj[key]
        }
      }

    }

    let newObj = {}

    diGui(newObj, obj)

7. 运用递归获取整个 DOM 树

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>

  </style>
</head>

<body>
  <div class="box">
    <div>
      电子产品
      <p>
        手机
        <b>iPhone</b>
        <b>华为</b>
        <b>小米</b>
      </p>
      <p>
        笔记本
        <b>戴尔</b>
        <b>外星人</b>
        <b>联想</b>
      </p>
    </div>
    <div>
      家具家电
      <p>
        家具产品
        <b>沙发</b>
        <b>桌子</b>
        <b>椅子</b>
      </p>
      <p>
        家电
        <b>冰箱</b>
        <b>空调</b>
      </p>
    </div>
  </div>



  <script>

    function giveMe(arr, ele) {
      for (let i = 0; i < ele.children.length; i++) {
        // 到现在我们就只能拿到 .box的子代元素
        arr.push(ele.children[i])
        // 所以我们现在直接调用这个函数就ok了
        giveMe(arr, ele.children[i])
      }
    }

    let box = document.querySelector('.box')

    let arr = []
    giveMe(arr, box)
    console.log(arr);
  </script>
</body>

</html>

8.递归写三级目录

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    .menu p {
      width: 100px;
      border: 3px solid;
      margin: 5px;
    }

    .menu>div p {
      margin-left: 10px;
      border-color: red;
    }

    .menu>div>div p {
      margin-left: 20px;
      border-color: green;
    }

    .menu>div>div>div p {
      margin-left: 30px;
      border-color: yellow;
    }
  </style>
</head>

<body>
  <div class="menu">
    <!-- <div>
        <p>第一级菜单</p>
        <div>
          <p>第二级菜单</p>
          <div>
            <p>第三级菜单</p>
          </div>
        </div>
      </div> -->
  </div>
  <script>
    //服务器返回一个不确定的数据结构,涉及到多重数组嵌套
    let arr = [
      {
        type: '电子产品',
        data: [
          {
            type: '手机',
            data: ['iPhone手机', '小米手机', '华为手机']
          },
          {
            type: '平板',
            data: ['iPad', '平板小米', '平板华为']
          },
          {
            type: '智能手表',
            data: []
          }
        ]
      },
      {
        type: '生活家居',
        data: [
          {
            type: '沙发',
            data: ['真皮沙发', '布沙发']
          },
          {
            type: '椅子',
            data: ['餐椅', '电脑椅', '办公椅', '休闲椅']
          },
          {
            type: '桌子',
            data: ['办公桌']
          }
        ]
      },
      {
        type: '零食',
        data: [
          {
            type: '水果',
            data: []
          },
          {
            type: '咖啡',
            data: ['雀巢咖啡']
          }
        ]
      }
    ]


    function addEle(arr, ele) {
      for (let i = 0; i < arr.length; i++) {
        console.log(arr[i])
        // 1. 先创建空元素
        let div = document.createElement('div')
        // 2. 设置内容
        div.innerHTML = `<p> ${arr[i].type || arr[i]} </p>`
        // 3. 添加到DOM树
        ele.appendChild(div)
        //  如果是一级 或者 二级菜单, 则继续递归新增的元素 (如果只有一级二级菜单有data,三级菜单没有data,不需要继续递归了)
        if (arr[i].data) {
          addEle(arr[i].data, div)
        }
      };
    }

    addEle(arr, document.querySelector('.menu'))
  </script>
</body>

</html>

image.png