Bootstrap

JS进阶-深浅拷贝

学习目标:

  • 掌握深浅拷贝

学习内容:

  1. 浅拷贝
  2. 深拷贝

浅拷贝:

开发中我们经常需要复制一个对象。如果直接赋值会有下面问题:

 <title>直接复制对象的问题</title>
</head>

<body>
  <script>
    //一个obj对象
    const obj = {
      uname: 'pink',
      age: 18
    }
    const o = obj
    console.log(o)  //{uname: 'pink', age: 18}
    o.age = 20
    console.log(o)  //{uname: 'pink', age: 20}
    //但是obj对象里面的age值也发生了变化
    console.log(obj) //{uname: 'pink', age: 20}
  </script>

</body>

在这里插入图片描述
首先浅拷贝和深拷贝只针对引用类型。

  • 浅拷贝:拷贝的是地址。
  • 常见方法
  1. 拷贝对象:Object.assign( )/ 展开运算符{ ...obj }拷贝对象
 <title>浅拷贝</title>
</head>

<body>
  <script>
    const obj = {
      uname: 'pink',
      age: 18,
      family: {
        baby: '小pink'
      }
    }
    // 浅拷贝
    //1.展开运算符{ ...obj }拷贝对象
    // const o = { ...obj }
    // console.log(o)  //{uname: 'pink', age: 18}
    // o.age = 20
    // console.log(o) //{uname: 'pink', age: 20}
    // console.log(obj) //{uname: 'pink', age: 18}

    //另一种方法
    //2.Object.assign( )
    const o = {}
    Object.assign(o, obj)
    o.age = 20
    //更改对象里面的family还是会有影响
    o.family.baby = '老pink'
    console.log(o)  //{uname: 'pink', age: 20}
    console.log(obj) //{uname: 'pink', age: 18}
  </script>

</body>
  1. 拷贝数组:Array.prototype.concat()或者[...arr]

但是还有问题…

 <title>浅拷贝</title>
</head>

<body>
  <script>
    const obj = {
      uname: 'pink',
      age: 18,
      family: {
        baby: '小pink'
      }
    }
    // 浅拷贝
    //1.展开运算符{ ...obj }拷贝对象
    // const o = { ...obj }
    // console.log(o)  //{uname: 'pink', age: 18}
    // o.age = 20
    // console.log(o) //{uname: 'pink', age: 20}
    // console.log(obj) //{uname: 'pink', age: 18}

    //另一种方法
    //2.Object.assign( )
    const o = {}
    Object.assign(o, obj)
    o.age = 20
    //更改对象里面的family还是会有影响
    o.family.baby = '老pink'
    console.log(o)  //{uname: 'pink', age: 20}
    console.log(obj) //{uname: 'pink', age: 18}
  </script>

</body>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如果是简单数据类型拷贝值,引用数据类型拷贝的是地址(简单理解:如果是单层对象,没有问题,如果有多层就有问题)。

  • 小结:
  1. 直接赋值和浅拷贝有什么区别?
直接赋值只要是对象,都会相互影响,因为是直接拷贝对象栈里面的地址
浅拷贝如果是一层对象,不相互影响,如果出现多层对象拷贝还会相互影响
  1. 浅拷贝怎么理解?
拷贝对象之后,里面的属性值是简单数据类型直接拷贝值-
如果属性值是引用数据类型则拷贝的是地址-

深拷贝:

  • 深拷贝:拷贝的是对象,不是地址。
  • 常见方式
  1. 通过递归实现深拷贝

函数递归

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。

简单理解:函数内部自己调用自己,这个函数就是递归函数。

递归函数的作用和循环效果类似。

由于递归很容易发生"栈溢出"错误,所以必须要加退出条件return

 <title>递归函数</title>
</head>

<body>
  <script>
    let i = 1
    //fn就是递归函数
    function fn() {
      console.log(`这是第${i}`)
      if (i >= 6) {
        return
      }
      i++
      fn() //函数内部调用函数自己
    }
    fn()
  </script>

</body>
  • 练习-利用递归函数实现setTimeout模拟setInterval效果。
 <title>利用递归函数实现setTimeout模拟setInterval效果</title>
</head>

<body>
  <div></div>
  <script>
    function getTime() {
      document.querySelector('div').innerHTML = new Date().toLocaleString()
      setTimeout(getTime, 1000)  //定时器调用当前函数
    }
    getTime()

  </script>

</body>
  • 代码:简版
  <title>深拷贝2</title>
</head>

<body>
  <script>
    const obj = {
      uname: 'pink',
      age: 18,
      hobby: ['跳舞', '弹琴'],
      family: {
        baby: '小pink'
      }
    }
    const o = {}
    //拷贝函数
    function deepCopy(newObj, oldObj) {
      // k 索引号  oldObj[k]  ['跳舞', '弹琴']
      for (let k in oldObj) {
        //处理数组的问题  一定要先写数组  再写对象  不能颠倒
        if (oldObj[k] instanceof Array) {
          newObj[k] = []
          // newObj[k] 接受[] hobby
          //oldObj[k]  ['跳舞', '弹琴']
          deepCopy(newObj[k], oldObj[k])

        } else if (oldObj[k] instanceof Object) {
          newObj[k] = {}
          // newObj[k] 接受[] hobby
          //oldObj[k]  ['跳舞', '弹琴']
          deepCopy(newObj[k], oldObj[k])

        } else {
          //k是属性名  uname age   
          // oldObj[k] 是属性值  18
          // newObj[k] === o.uname  属性名
          newObj[k] = oldObj[k]
        }
      }
    }
    deepCopy(o, obj) //函数调用 两个参数  o是新对象  obj是旧对象
    console.log(o)  //{uname: 'pink', age: 18}
    o.age = 20
    o.hobby[0] = '撸猫'
    o.family.baby = '大pink'
    console.log(obj) //{uname: 'pink', age: 18}
    console.log([1, 23] instanceof Object)  //true



    //复习
    // const obj = {
    //     uname: 'pink',
    //     age: 18,
    //     hobby: ['跳舞', '弹琴']
    //   }
    // function deepCopy({ }, oldObj) {
    //   //k 属性名 oldObj[k] 属性值
    //   for (let k in oldObj) {
    //     //处理数组的问题
    //     newObj[k] = oldObj[k]
    //     // o.uname = 'pink'
    //     // newObj.k  = 'pink'
    //   }
    // }

  </script>

</body>
  1. js库lodash里面cloneDeep内部实现了深拷贝
 <title>js库lodash里面cloneDeep内部实现了深拷贝</title>
</head>

<body>
  <script src="./lodash.min.js"></script>
  <script>
    const obj = {
      uname: 'pink',
      age: 18,
      hobby: ['跳舞', '弹琴'],
      family: {
        baby: '小pink'
      }
    }
    //语法:_.cloneDeep(要被克隆的对象)
    const o = _.cloneDeep(obj)
    console.log(o)
    o.family.baby = '老pink'
    console.log(obj)
  </script>

</body>
  1. 通过JSON.stringfy()实现
 <title>通过JSON.stringfy()实现</title>
</head>

<body>
  <script>
    const obj = {
      uname: 'pink',
      age: 18,
      hobby: ['跳舞', '弹琴'],
      family: {
        baby: '小pink'
      }
    }
    // 把对象转换为 JSON 字符串
    // console.log(JSON.stringify(obj))
    const o = JSON.parse(JSON.stringify(obj))
    console.log(o)
    o.family.baby = '123'
    console.log(obj)
  </script>

</body>
  • 小结:
  1. 实现深拷贝三种方式?
方法说明
自己利用递归函数书写深拷贝。-
利用js库loadash里面的_.cloneDeep( )const o = _.cloneDeep(obj)
利用JSON字符串转换 const o = JSON.parse(JSON.stringify(obj))
;