js高级-递归 + 深拷贝 + 浅拷贝 (对象 和 数组)

第七章:函数递归

递归: 函数自己调用自己

递归,一般都要写一个结束的条件,不然会因为内存溢出(超过了最大的堆栈大小),

而报错 Maximum call stack size exceeded

用递归来实现 1 + 2 + 3 + 4 + … + n

// 递归推导过程:
// n = 3,    3 + getSum(3 - 1) -> 2 + 1
// n = 2,    2 + getSum(2 - 1) -> 1
// n = 1,    1

function getSum(n) {
     
    // 递归结束的条件
    if (n === 1) {
     
        return 1;
    }
    return n + getSum(n - 1); // 不断调用getSum()函数,直到满足条件退出
}

console.log(getSum(3)); // 结果是:6

计算阶乘的递归函数

需求:1 * 2 * 3…* n

// 递归推导过程:
// n = 3,  3 * fn(3 - 1)
// n = 2,  2 * fn(2 - 1)
// n = 1,  1

function fn(n) {
     
    if (n === 1) {
     
    	return 1;
    }
    return n * fn(n - 1);
}
console.log(fn(3)); // 1*2*3   结果是:6
console.log(fn(4)); // 1*2*3*4 结果是:24

斐波那契数列

1、1、2、3、5、8、13、21、34、

// 从第三个数开始:第三个数是前两个数之和
// 第n个数是 n-1个数 和 n-2 个数之和(n>=3)

function fn(n) {
     
    if (n === 1 || n === 2) {
     
        return 1;
    }
    return fn(n - 1) + fn(n - 2);
}

console.log(fn(3)); // 结果为:2
console.log(fn(5)); // 结果为:5

对象的拷贝


<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>Documenttitle>
head>

<body>
  <script>
    // .................对象的拷贝..............
    var obj1 = {
      
      name: 'zs',
      age: 18,
      sex: '男'
    }

    var obj2 = {
      };

    // 遍历对象中的成员
    for (var key in obj1) {
      
      //  obj1[key]              //属性作为变量可以采用[]形式
      obj2[key] = obj1[key];
    }

    // 修改obj1的成员,此时不会影响obj2
    obj1.name = 'xx';
    console.dir(obj2);

    // ............封装函数  - 把o1 的成员,复制给o2......

    var obj1 = {
      
      name: 'zs',
      age: 18,
      sex: '男'
    }

    var obj2 = {
      };

    function copy(o1, o2) {
      
      for (var key in o1) {
      
        o2[key] = o1[key];
      }
    }
    copy(obj1, obj2);
    console.dir(obj2);
    
  script>
body>

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>Documenttitle>
head>

<body>
  <script>
    // 注意:只有复杂数据类型:才有拷贝的价值!
    // 然后复杂数据类型里面:再分 简单数据类型 和 复杂数据类型
    // (1)在浅拷贝中:
    // 简单数据类型:复制值;一方修改不会影响另一方
    // 复杂数据类型:复制地址;一方修改会影响另一方
    // (2)而在深拷贝中:
    // 简单数据类型:一方修改不会影响另一方
    // 复杂数据类型:一方修改不会影响另一方


    // ...............对象的拷贝......................
    // 简单数据类型:复制值;一方修改不会影响另一方
    // 复杂数据类型:复制地址;一方修改会影响另一方
    // .....浅拷贝  封装函数  - 把o1 的成员,复制给o2.....

    var obj1 = {
      
      name: 'zs',
      age: 18,
      sex: '男',
      dog: {
      
        name: '金毛',
        age: 2,
        yellow: '黄色'
      }
    }

    var obj2 = {
      };

    function copy(o1, o2) {
      
      for (var key in o1) {
      
        o2[key] = o1[key];
      }
    }
    copy(obj1, obj2);

    // 修改obj1中的成员
    obj1.name = 'xxxx'; // 简单数据类型
    obj1.dog.name = '大黄'; // 复杂数据类型

    console.dir(obj2);
  script>
body>

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>Documenttitle>
head>

<body>
  <script>
    // 注意:只有复杂数据类型:才有拷贝的价值!
    // 然后复杂数据类型里面:再分 简单数据类型 和 复杂数据类型
    // (1)在浅拷贝中:
    // 简单数据类型:复制值;一方修改不会影响另一方
    // 复杂数据类型:复制地址;一方修改会影响另一方
    // (2)而在深拷贝中:
    // 简单数据类型:一方修改不会影响另一方
    // 复杂数据类型:一方修改不会影响另一方

    // .............对象的拷贝--深拷贝................

    var obj1 = {
      
      name: 'zs',
      age: 18,
      sex: '男',
      dog: {
      
        name: '金毛',
        age: 2,
        yellow: '黄色'
      },
      friends: ['lilei', 'hanmeimei']
    }

    var obj2 = {
      };
    var arr = [];

    // // 证明:数组也是对象
    // console.log(arr instanceof Array); // true
    // console.log(arr instanceof Object); // true

    // 深拷贝
    // 判断一个变量(属性也相当于变量)的类型: instanceof 
    // 情形一:如果key是数组类型
    // 分析:1.首先我们给o2增加属性[key],它的值应该等于?
    //        我不能像之前的基本类型一样直接赋值,基本类型直接赋值就是把值直接赋值过去
    //        如果是复杂类型复制的是另一个对象的引用式地址
    //        所以如果我们想把对象在内存中复制一份,我们要做一次拷贝的操作
    //        如果是数组先初始化一个空数组,因为数组的本质也是对象;我们可以把数组的索引看成属性
    //        我们把o1中friends属性的第0项拷贝到02的数组[]中;接着拷贝第二项...o2[key] = [];

  //  2.把数组的索引看成属性,接着把数组看成对象;我们要拷贝对象的所有属性,我们就可以调用deepCopy方法
  // 用递归的方式解决问题 o1[key]是个属性但这个属性也是一个对象;我们将这个对象的所有成员拷贝给 o2[key]

    // 情形一:如果key是复杂类型 Object?  {}
    // 分析:1.首先我们给o2增加属性[key],因为它是对象所以初始化为空对象{}
    //      2.o1[key]是个属性但这个属性也是一个对象;我们将这个对象的所有成员拷贝给 o2[key]

    function deepCopy(o1, o2) {
      
      for (var key in o1) {
      
        if (o1[key] instanceof Array) {
      

          console.log(key);
          // 1.如果key是数组类型 Array?   []
          o2[key] = [];
          deepCopy(o1[key], o2[key]);

        } else if (o1[key] instanceof Object) {
      

          // 2.如果key是复杂类型 Object?  {}
          o2[key] = {
      };
          deepCopy(o1[key], o2[key]);

        } else {
      

          // 3.如果key这个属性 是基本类型
          o2[key] = o1[key];

        }
      }
    }
    deepCopy(obj1, obj2); // obj1里面的内容 拷贝给 obj2

    // 修改obj1中的成员
    obj1.name = 'xxxx';
    obj1.dog.name = '大黄';
    obj1.friends[0] = 'xxxx';

    console.dir(obj1);
    console.dir(obj2);
  script>
body>

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>Documenttitle>
head>

<body>
  <script>
    // 注意:只有复杂数据类型:才有拷贝的价值!
    // 然后复杂数据类型里面:再分 简单数据类型 和 复杂数据类型
    // (1)在浅拷贝中:
    // 简单数据类型:复制值;一方修改不会影响另一方
    // 复杂数据类型:复制地址;一方修改会影响另一方
    // (2)而在深拷贝中:
    // 简单数据类型:一方修改不会影响另一方
    // 复杂数据类型:一方修改不会影响另一方

    // .............对象的拷贝--深拷贝................

    var obj1 = {
      
      name: 'zs',
      age: 18,
      sex: '男',
      dog: {
      
        name: '金毛',
        age: 2,
        yellow: '黄色'
      },
      friends: ['lilei', 'hanmeimei']
    }

    var obj2 = {
      };
    var arr = [];

    // // 证明:数组也是对象
    // console.log(arr instanceof Array); // true
    // console.log(arr instanceof Object); // true

    // 深拷贝
    // 判断一个变量(属性也相当于变量)的类型: instanceof 
    // 情形一:如果key是数组类型
    // 分析:1.首先我们给o2增加属性[key],它的值应该等于?
    //        我不能像之前的基本类型一样直接赋值,基本类型直接赋值就是把值直接赋值过去
    //        如果是复杂类型复制的是另一个对象的引用式地址
    //        所以如果我们想把对象在内存中复制一份,我们要做一次拷贝的操作
    //        如果是数组先初始化一个空数组,因为数组的本质也是对象;我们可以把数组的索引看成属性
    //        我们把o1中friends属性的第0项拷贝到02的数组[]中;接着拷贝第二项...o2[key] = [];

  //  2.把数组的索引看成属性,接着把数组看成对象;我们要拷贝对象的所有属性,我们就可以调用deepCopy方法
  // 用递归的方式解决问题 o1[key]是个属性但这个属性也是一个对象;我们将这个对象的所有成员拷贝给 o2[key]

    // 情形一:如果key是复杂类型 Object?  {}
    // 分析:1.首先我们给o2增加属性[key],因为它是对象所以初始化为空对象{}
    //      2.o1[key]是个属性但这个属性也是一个对象;我们将这个对象的所有成员拷贝给 o2[key]

    function deepCopy(o1, o2) {
      
      for (var key in o1) {
      
        if (o1[key] instanceof Array) {
      

          console.log(key);
          // 1.如果key是数组类型 Array?   []
          o2[key] = [];
          deepCopy(o1[key], o2[key]);

        } else if (o1[key] instanceof Object) {
      

          // 2.如果key是复杂类型 Object?  {}
          o2[key] = {
      };
          deepCopy(o1[key], o2[key]);

        } else {
      

          // 3.如果key这个属性 是基本类型
          o2[key] = o1[key];

        }
      }
    }
    deepCopy(obj1, obj2); // obj1里面的内容 拷贝给 obj2

    // 修改obj1中的成员
    obj1.name = 'xxxx';
    obj1.dog.name = '大黄';
    obj1.friends[0] = 'xxxx';

    console.dir(obj1);
    console.dir(obj2);
  script>
body>

html>

菜单树


遍历 DOM 树


<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>遍历DOM树title>
head>

<body>
  <h1>遍历 DOM 树h1>
  <p style="color: green;">Tip: 可以在遍历的回调函数中任意定制需求p>
  <div>
    <ul id="list">
      <li>123li>
      <li>456li>
      <li>789li>
    ul>
  div>
  <script>
  // .....遍历指定元素下所有的子元素:应用如:注册事件或者设置样式..........
  // loadTree的时候我们找到了所有的子元素,并且把它们打印出来;这样做没有什么实际意义
  // 我们希望找到这些子元素之后,可以为子元素注册事件或者设置样式...
  // 让外面的人操作我们找到的这些子元素;
  // 我们做这些操作需要指定一些代码,这些代码我们可以通过函数传递进来callback,通过callback不停的调用回调函数
  // 中途用户有可能忘记传递参数了,所以进行if判断,保证用户传递内容

    function loadTree(parent, callback) {
      
      for (var i = 0; i < parent.children.length; i++) {
      
        // 遍历第一级子元素
        var child = parent.children[i];
        console.log(child);

        if (callback) {
      
          // 处理找到的子元素
          callback(child); // 调用callback的时候,把child传给function(element)
        }

        // 递归调用
        loadTree(child); // 此时child作为父元素再找child里面的子元素
      }
    }

    var ul = document.getElementById('list');

    loadTree(ul, function (element) {
      

      // 为所有子元素注册点击事件
      element.onclick = function () {
      
        console.log(this.innerText);
        this.style.color = 'red';
      }

    });

 // 构思:loadTree的第一个参数:找谁里面的子元素 ;第二个参数:找到子元素后干什么(传入函数--> callback进行调用)
 // 需求:给ul的所有子元素注册点击事件
 // 1.获取ul元素
 // 2.调用loadTree
  script>
body>

html>

你可能感兴趣的:(javascript)