深拷贝-浅拷贝-引用赋值的写法

43 篇文章 4 订阅
对象相互赋值的一些关系,分别包括:
  • 引入的赋值:指向同一个对象,相互之间会影响;
  • 对象的浅拷贝:只是浅层的拷贝,内部引入对象时,依然会相互影响;
  • 对象的深拷贝:两个对象不再有任何关系,不会相互影响;

如果有一个对象info,想要拷贝里面的内容,有三种方式。

const info ={
      name: "zzz",
      age: 18,
      friend: {
        name: "www"
      }
    }

方式一:使用引用赋值

info和obj1是相同的引用,修改obj1的name也会影响到info的name。

//引用赋值
    const obj1 = info
    console.log(obj1)

方式二:浅拷贝

//浅拷贝
    const obj2 = {...info}
    obj2.name = "jx"
    console.log(obj2.name) //jx

使用展开运算符,拷贝了一个新的对象obj2,修改里面的name,info不会跟着改变。

const obj2 = {...info}
    obj2.friend.name = "jx"
    console.log(obj2.friend.name) //jx
    console.log(info.friend.name) //jx

但是如果修改的是对象,info的对象也会跟着发生变化。

浅拷贝可以拷贝原始类型,不能拷贝复杂类型比如对象等。

还有一种浅拷贝的方式。

const obj3 = Object.assign({}, info)

Object.assign方法,将后面的info拷贝到前面的{}对象中,并且返回给obj3。

方式三:深拷贝

深拷贝实现方式有两种:使用JSON方法,自己实现

使用JSON方法

const obj4 = JSON.parse(JSON.stringify(info))

这个obj4完全是一个新的对象,修改对象的内容,info的对象内容也不会跟着改变。

但是使用JSON方法有很大的缺陷就是当info里面有其他的值时。

const info ={
      name: "zzz",
      age: 18,
      friend: {
        name: "www"
      },
      running: function() {},
      [Symbol()]: "abc"
    }

深拷贝下来的内容是没有函数和Symbol的。

我们可以自己手写深拷贝函数

深拷贝函数的基本类型和对象的实现

首先需要创建一个函数用来判断一个value是否为对象。

注意不能用typeof 来判断value是否为null,因为null用typeof判断,出来的是object。

function isObject(value){
    const valueType = typeof value
    return (value !== null) && (valueType === "function" || valueType === "function")
}
function deepCopy(originValue){
    //如果是原始类型就直接返回
    if(!isObject(originValue)){
        return originValue
    }
    //创建一个新的对象
    const newObj = {}
    //遍历要拷贝的对象,取出它的key
    //递归 重新判断要拷贝的对象里面是否还有对象
    for(const key in originValue){
        newObj[key] = deepCopy(originValue[key])
    }
    //返回新对象
    return newObj
}

关键的代码是,使用递归不断判断要拷贝的对象里面是否还有对象。

用一个对象来实验一下深拷贝的效果吧。这个对象暂时还没有函数和Symbol类型的判断,后面会做优化的。

const info ={
      name: "zzz",
      age: 18,
      friend: {
        name: "www",
        address: {
          name: "sz",
          detail: "lky"
        }
      },
    }

const newObj = deepCopy(info)
console.log(newObj)

深拷贝成功了!

深拷贝函数的数组拷贝

有时候我们需要拷贝数组,在JavaScript中,数组也是一个对象,上面的代码中创建的是一个新的对象,但不一定要创建的是新对象,也有可能是新数组,所以需要先区分对象和数组,再创建对象或者数组。

function isObject(value) {
      const valueType = typeof value
      return (value !== null) &&(valueType === "object" || valueType ==="function")
    }
    function deepCopy(originValue) {
      //如果是原始类型就直接返回
      if(!isObject(originValue)) {
        return originValue
      }
      //判断是数组还是对象
      
      const newObj = Array.isArray(originValue)? [] :{}
      for(const key in originValue){
        newObj[key] = deepCopy(originValue[key])
      }
      return newObj
    }

 关键的一步是通过Array的isArray判断传入的是对象还是数组。

 我们创建一个books数组来验证一下是否可以判断对象还是数组来拷贝。

const books = [
      { name:"book1", price: 1 },
      { name:"book2", price: 2 },
      { name:"book3", price: 3 },
    ] 
    const newArray = deepCopy(books)
    console.log(newArray)

拷贝的是一个数组。

深拷贝函数的Set拷贝

有的时候,深拷贝的内容有Set,如果不知道Set是什么的话,可以看这篇JavaScript中Set的使用,Set和数组类似,但是Set的元素是不能重复的,所以它常用于去重。

创建一个set,把它放进info对象里面。

    const set = new Set(["zzz", "wjx", "lky"])
    const info = {
      name: "zzz",
      age: 18,
      friend: {
        name: "www",
        address: {
          name: "sz",
          detail: "lky"
        }
      },
      set: set
    }
    function isObject(value) {
      const valueType = typeof value
      return (value !== null) &&(valueType === "object" || valueType ==="function")
    }

    function deepCopy(originValue) {
      //如果是原始类型就直接返回
      if(!isObject(originValue)) {
        return originValue
      }
      //判断是否是set
      if(originValue instanceof Set) {
        const newSet = new Set()
        for(const setItem of originValue) {
          newSet.add(deepCopy(setItem))
        }
        return newSet
      }
      //判断是数组还是对象
      const newObj = Array.isArray(originValue)? [] :{}
      for(const key in originValue){
        newObj[key] = deepCopy(originValue[key])
      }
      return newObj
    }

 先判断传入的值是不是Set,创建新的Set,遍历Set,把遍历的元素一个个放到新的Set里面。

可以拷贝Set了。

深拷贝函数的函数返回

函数是不需要深拷贝的,因为函数是用来执行的,如果再拷贝一个函数,会消耗性能。 

if(typeof originValue === "function") {
        return originValue
}

所以遇到函数的时候直接返回了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

至尊绝伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值