javaScript中的深浅拷贝

首先明确 javaScript 中简单数据类型由于变量中保存的是数据的字面量,因此只需用’='赋值的方式进行拷贝即可。javaScript 的深浅拷贝只针对于复杂数据类型,例如数组、对象。

使用’='拷贝存在的问题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 数组类型
    const arr = [1, 2, 3]

    // 直接赋值
    const newArr = arr
    console.log(newArr)  // [1, 2, 3]

    // 改变newArr中的数据
    newArr[0] = 4
    console.log(arr)  // [4, 2, 3]

    // 对象类型
    const obj = {
      name: '小明',
      age: 18
    }

    // 直接赋值
    const newObj = obj
    console.log(newObj)  // {name: '小明', age: 18}

    // 改变newObj中的数据
    newObj.age = 20
    console.log(obj)  // {name: '小明', age: 20}
  </script>
</body>
</html>

当使用’='赋值的方式进行复杂数据类型的拷贝时,可以得到该数据的副本,当对副本进行修改时,原数据也会发生改变,这是因为它们保存的是数据的地址。

浅拷贝

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 数组类型
    const arr = [1, 2, 3]

    // 浅拷贝方式一:
    const newArr = Array.prototype.concat(arr)
    console.log(newArr)  // [1, 2, 3]

    // 改变newArr中的数据
    newArr[0] = 4
    console.log(arr)  // [1, 2, 3]

    // 浅拷贝方式二:
    const newArr2 = [...arr]
    console.log(newArr2)  // [1, 2, 3]

    // 改变newArr2中的数据
    newArr2[0] = 5
    console.log(arr)  // [1, 2, 3]

    // 对象类型
    const obj = {
      name: '小明',
      age: 18
    }

    // 浅拷贝方式一:
    const newObj = {}
    Object.assign(newObj, obj)
    console.log(newObj)  // {name: '小明', age: 18}

    // 改变newObj的数据
    newObj.age = 20
    console.log(obj)  // {name: '小明', age: 18}

    // 浅拷贝方式二:
    const newObj2 = {...obj}
    console.log(newObj2)  // {name: '小明', age: 18}

    // 改变newObj2的数据
    newObj2.age = 30
    console.log(obj)  // {name: '小明', age: 18}
  </script>
</body>
</html>

数组和对象的两种浅拷贝方式,不仅能够拷贝出原数据,并且修改数据不改变原数据,这是因为浅拷贝是拷贝的地址。但是浅拷贝依然存在一个问题,如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 数组类型
    const arr = [1, 2, [3, 4]]

    // 浅拷贝:
    const newArr = Array.prototype.concat(arr)
    console.log(newArr)  // [1, 2, [3, 4]]

    // 改变newArr中的数据
    newArr[2][0] = 5
    console.log(arr)  // [1, 2, [5, 4]]

    // 对象类型
    const obj = {
      name: '小明',
      age: 18,
      family: {
        mother: 'mom',
        father: 'dad'
      }
    }

    // 浅拷贝:
    const newObj = {}
    Object.assign(newObj, obj)
    console.log(newObj)  // {name: '小明', age: 18, family: {mother: 'mom', father: 'dad'}}

    // 改变newObj的数据
    newObj.family.mother = 'mom2'
    console.log(obj)  // {name: '小明', age: 18, family: {mother: 'mom2', father: 'dad'}}
  </script>
</body>
</html>

当数组或是对象中又嵌套了数组或对象,改变这里面的值依然会影响原数据。

深拷贝

深拷贝,拷贝的是对象本身,而不是地址了,因此,无论嵌套了多少层,对其修改都不会影响原数据。
这里介绍三种深拷贝的方式:

1、利用递归自定义深拷贝函数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 递归实现深拷贝
    function deepCopy(newObj, oldObj) {
      for (let k in oldObj) {
        if (oldObj[k] instanceof Array) {
          newObj[k] = []
          deepCopy(newObj[k], oldObj[k])
        } else if (oldObj[k] instanceof Object) {
          newObj[k] = {}
          deepCopy(newObj[k], oldObj[k])
        } else {
          newObj[k] = oldObj[k]
        }
      }
    }

    // 数组类型
    const arr = [1, 2, [3, 4]]

    // 深拷贝
    const newArr = []
    deepCopy(newArr, arr)
    console.log(newArr)  // [1, 2, [3, 4]]

    // 改变newArr中的数据
    newArr[2][0] = 5
    console.log(arr)  // [1, 2, [3, 4]]

    // 对象类型
    const obj = {
      name: '小明',
      age: 18,
      family: {
        mother: 'mom',
        father: 'dad'
      }
    }

    // 深拷贝
    const newObj = {}
    deepCopy(newObj, obj)
    console.log(newObj)  // {name: '小明', age: 18, family: {mother: 'mom', father: 'dad'}}

    // 改变newObj中的数据
    newObj.family.mother = 'mom2'
    console.log(obj)  // {name: '小明', age: 18, family: {mother: 'mom', father: 'dad'}}
  </script>
</body>
</html>

2、利用lodash库中的cloneDeep方法实现深拷贝

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="js/lodash.min.js"></script>
  <script>
    // 数组类型
    const arr = [1, 2, [3, 4]]

    // 深拷贝
    const newArr = _.cloneDeep(arr)
    console.log(newArr)  // [1, 2, [3, 4]]

    // 改变newArr中的数据
    newArr[2][0] = 5
    console.log(arr)  // [1, 2, [3, 4]]

    // 对象类型
    const obj = {
      name: '小明',
      age: 18,
      family: {
        mother: 'mom',
        father: 'dad'
      }
    }

    // 深拷贝
    const newObj = _.cloneDeep(obj)
    console.log(newObj)  // {name: '小明', age: 18, family: {mother: 'mom', father: 'dad'}}

    // 改变newObj中的数据
    newObj.family.mother = 'mom2'
    console.log(obj)  // {name: '小明', age: 18, family: {mother: 'mom', father: 'dad'}}
  </script>
</body>
</html>

3、通过JSON.stringify()实现深拷贝

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="js/lodash.min.js"></script>
  <script>
    // 数组类型
    const arr = [1, 2, [3, 4]]

    // 深拷贝
    const newArr = JSON.parse(JSON.stringify(arr))
    console.log(newArr)  // [1, 2, [3, 4]]

    // 改变newArr中的数据
    newArr[2][0] = 5
    console.log(arr)  // [1, 2, [3, 4]]

    // 对象类型
    const obj = {
      name: '小明',
      age: 18,
      family: {
        mother: 'mom',
        father: 'dad'
      }
    }

    // 深拷贝
    const newObj = JSON.parse(JSON.stringify(obj))
    console.log(newObj)  // {name: '小明', age: 18, family: {mother: 'mom', father: 'dad'}}

    // 改变newObj中的数据
    newObj.family.mother = 'mom2'
    console.log(obj)  // {name: '小明', age: 18, family: {mother: 'mom', father: 'dad'}}
  </script>
</body>
</html>

总结

1、浅拷贝的方式:

数组:Array.prototype.concat()、[…arr]
对象: Object.assign()、{…obj}

2、深拷贝的方式:

递归实现:

function deepCopy(newObj, oldObj) {
      for (let k in oldObj) {
        if (oldObj[k] instanceof Array) {
          newObj[k] = []
          deepCopy(newObj[k], oldObj[k])
        } else if (oldObj[k] instanceof Object) {
          newObj[k] = {}
          deepCopy(newObj[k], oldObj[k])
        } else {
          newObj[k] = oldObj[k]
        }
      }
    }

引入lodash库调用cloneDeep()函数实现;
通过JSON.parse(JSON.stringify())实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值