递归——函数在内部自己调用自己,那么该函数是递归函数 & 作用和循环效果一样 & 要加推出条件return,否则发生栈溢出,导致死循环 & 递归给数组中对象添加属性 & toString()和随机数

递归——函数在内部自己调用自己,那么该函数是递归函数 & 作用和循环效果一样 & 要加推出条件return,否则发生栈溢出,导致死循环 & 递归给数组中对象添加属性 & toString()和随机数

1、概念

一个方法在执行过程中调用自身,就称为递归

注意: 调用重载方法不是递归,不能光看方法名字

递归的关键: 方法调用时,程序会停在方法调用处,直到方法返回继续执行

1.1、递归的使用场景
  1. 一个问题可拆分为若干个子问题的解
  2. 拆分后的子问题与原问题除问题规模不同,解决思路相同
  3. 存在递归的终止条件

注意: 所谓终止条件就是不借助任何其他函数,就能直接知道求出问题答案

递归代码=终止条件+当前不借助任何方法就能实现的步骤+剩下的问题利用相同的方法解决

1.2、递归函数

一个函数在内部自己调用自己,那么这个函数就是递归函数

递归函数的作用其实和循环效果一样

  • 循环最怕遇到的是死循环,而递归也很容易发生“栈溢出”的错误,所以必须要加推出条件return
<script>
// 会发生栈溢出的错误
function fun(){
   fun();
}
fun();
</script>

为递归函数添加return退出条件

<script>
  // 输出六次
  var num = 0;
  function fun() {
    console.log("hello"); // 会输出六次
    if (num == 5) {
      return; // 递归里必须加推出条件
    } else {
      num++;
    }
    fun();
  }
  fun();
</script>
2、使用递归代替循环

递归是函数调用自身的操作。

//依次打印1~10
for (var i = 1; i <= 10; i++) {
    console.log(i);
}


//借用递归实现
function fn(e) {
    console.log(++e);
    if (e === 10) {
        return
    }
    fn(e)
}
fn(0)
  • 以上就利用递归实现了依次输出1~10,e初始化为0,打印e++所以输出1,当e等与10的时候结束,否则继续调用函数自身,依次类推,直至达到结束条件。

为了便于理解,示例:计算数组内元素前 n 的元素乘积。

1、使用 for 循环, 可以这样做:

<script>
  let list = [1,2,3,4,5,6]
  function multiply(arr, n) {
    var product = 1;
    for (var i = 0; i < n; i++) {
        product *= arr[i];
    }
    return product;
  }

  console.log(multiply(list,4)) ;  // 24
</script>

2、递归写法,注意代码里的 multiply(arr, n) == multiply(arr, n - 1) * arr[n - 1]。 这意味着可以重写multiply以调用自身而无需依赖循环。

<script>
  let list = [1,2,3,4,5,6]
  function multiply(arr, n) {
    if (n <= 0) {
      return 1;
    } else {
      return multiply(arr, n - 1) * arr[n - 1];
    }
  }
  console.log(multiply(list,4)) ;  // 24
</script>

在multiply函数里,

  • n <= 0 时,返回 1。

  • 在 n 比 0 大的情况里,函数会调用自身,参数 n 的值为 n - 1。

函数以相同的方式持续调用 multiply,直到 n <= 0 为止。

所以,所有函数都可以返回,原始的 multiply 返回结果。

注意: 递归函数在没有函数调用时(在这个例子中,是当 n <= 0 时)必需有一个跳出结构,否则永远不会执行完毕。

3、实例
3.1、获取数组每一项value值
<script>
  let list = [2, 4, 6, 8]
  //依次打印数组value值
  // 1、for循环方式
  for (var i = 0; i < list.length; i++) {
    console.log('循环', list[i]);  // 2 4 6 8
  }
  // 2、递归方式
  function fn(arr, e) {
    console.log(arr[e]);   // 2 4 6 8
    ++e
    if (e === arr.length) {
      return
    }
    fn(arr, e)
  }
  fn(list, 0)
</script>
3.2、数组前几位求和
<script>
  let list = [1,2,3,4,5,6]
  function sum(arr, n) {
  // 只修改这一行下面的代码
  if(n<=0){
    return 0;
  }else if(n==1){
    return arr[0]
  }else{  
    return arr[n-1]+sum(arr,n-1)
  }

  // else if(n==1) return arr[0];
  // else return arr[n-1]+sum(arr,n-1) 
  // 只修改这一行上面的代码
}

  console.log(sum(list,4)) ;  // 10
</script>
3.3、给对象数组每一个对象添加属性或增加唯一标识
<script>
  let list = [{ name: '小红', id: 0 }, { name: '小明', id: 1 }]
  console.log('原始',list);
  //依次打印数组value值
  // 1、for循环方式
  for (var i = 0; i < list.length; i++) {
    list[i].age = 'China'
    list[i].ids = Math.random().toString(36).substr(2)
    console.log('循环', list[i]);  
  }
  // 2、递归方式
  function fn(arr, e) {
    arr[e].age = '中国'
    arr[e].ids = Math.random().toString(36).substr(2)
    console.log('递归',arr[e]);
    ++e
    if (e === list.length) {
      return
    }

    fn(arr, e)
  }
  fn(list, 0)
</script>

递归-显示

在这里插入图片描述

随机数

console.log(Math.random())  // 0.8187707720153985
console.log(Math.random().toString(36))  // '0.tuchtcpa9h'
console.log(Math.random().toString(36).substr(2))  // 'tuchtcpa9h'
附:toString使用方法

Number类型的toString()方法比较特殊,有默认模式和基模式两种。

1、默认模式的例子:

<script type="text/javascript">
     var num1 = 10;
     var num2 = 10.0;
     var num3 = 10.5;
     alert(num1.toString());//输出10
     alert(num2.toString());//输出10
     alert(num3.toString());//输出10.5
</script>

无论你用什么表示法声明数字,默认模式只是按十进制返回。

2、基模式的例子:

<script type="text/javascript">
   var num1 = 10.5;
   alert(num1.toString(2));//输出1010.1
   alert(num1.toString(8));//输出12.4
   alert(num1.toString(16));//输出a.8
</script>

很明显,基模式就是把数值型转换成相应的进制。

3.4、对象数组中,取出最后一层children数据
<script>
  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: "沐浴露" }] }
          ]
        }
      ]
    }]
  // 需求:取出最后一层children数据
  var recursiveFunction = function () {  // 匿名函数写法
    var str = ''
    var getStr = function (list) {
      list.forEach(item => {
        if (item.children) {
          getStr(item.children)
        } else {
          str += item.name + ';'
        }
      })
    }
    getStr(data)
    console.log(str) // 青苹果;红苹果;北方米饭;南方米饭;联想电脑;苹果电脑;锄头;锤子;洗发水;沐浴露;
  }
  recursiveFunction()
</script>
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值