ECMAScript-浅拷贝和深拷贝

一、ECMAScript-浅拷贝和深拷贝
1. 概念

深拷贝:拷贝的对象是新的对象,跟原来的对象不存在共享属性。

浅拷贝:拷贝的对象只是引用原对象的属性。

图解:

我们现在有一个对象在内存中,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ig47tmeY-1603437827292)(../ECMAScript-imgs/image-20201023150232816.png)]

深拷贝:是两个完全独立的个体

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KEzn3udO-1603437827295)(../ECMAScript-imgs/image-20201023150254593.png)]

浅拷贝:对象和函数部分只是引用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8aPFCL0l-1603437827298)(../ECMAScript-imgs/image-20201023150157541.png)]

2. Object.assign()存在的问题
// Object.assign()常常被用来拷贝对象,但是这种拷贝只是简单的拷贝,不能进行深层次的拷贝,
// 原因:Object.assign()在进行复杂对象的拷贝的时候,只是把引用地址进行的替换,并没有真正的拷贝值
// 简单对象
let target = {
    d: 2,
    e: 3,
    f: 4
}

let source = {
 		g: 4
}
Object.assign(target, source)
console.log(target) // {d: 2, e: 3, f: 4, g: 4} 正常

// 复杂对象
let target = {
  a: {
    b: {
      c: 1
    },
    d: 2,
    e: 3,
    f: 4
  }
}

let source = {
  a: {
    b: {
      c: 1
    },
    d: 2,
    e: 3
  }
}
Object.assign(target, source)
console.log(JSON.stringify(target)) // {"a":{"b":{"c":1},"d":2,"e":3}} 丢失了f

// 拷贝出来的值,值改变两者都不影响,叫深拷贝
let a = 5
let b = a
a = 6
console.log(a, b) // 6 5

// 拷贝出来的值,值改变影响到另一个值,叫浅拷贝
let obj1 = {
  name: 'zhangsan',
  age: 30
}
let obj2 = obj1
console.log(JSON.stringify(obj1)) // {"name":"zhangsan","age":30}
obj1.name = 'lisi' // 改变obj1的值
console.log(JSON.stringify(obj2)) // {"name":"lisi","age":30} obj2的值却改变了
3. 其他拷贝也存在的问题
// 扩展符
const newObj = {...obj}
// Object.creact()
const newObj = Object.creact({},obj)
4. 怎么去实现一个深拷贝
// 方式一:缺陷:如果对象中存在方法则转化就会失败
// 通过JSON.stringify()和JSON.parse()
let obj1 = {
  name: 'zhangsan',
  age: 30,
  study(){
    console.log(this.name)
  }
}
// 先通过JSON.stringify()将其转换成json格式的字符串
let str = JSON.stringify(obj1)
// 再转换成json对象
let obj2 = JSON.parse(str)
// 更改obj1属性的值
obj1.name = 'lisi'
console.log(obj2) // {name: "zhangsan", age: 30} 并未改变,但是方法丢失了

// 方式二:自己实现
let checkType = data => {
  return Object.prototype.toString.call(data).slice(8, -1)
}

console.log(checkType(function(){
  console.log('1111')
}))

let deepClone = target => {
  let targetType = checkType(target)
  let result
  if (targetType === 'Object') {
    result = {}
  } else if (targetType === 'Array') {
    result = []
  } else{
    return target
  }

  for(let key in target) {
    let value = target[key]
    let valueType = checkType(value)
    if(valueType === 'Object' || valueType === 'Array'){
      result[key] = deepClone(value)
    } else if (valueType === 'Function') {
      result[key] = target[key].bind(result)
    } else {
      result[key] = value
    }
  }
  return result
}

// 验证一:
let arr1 = [1, 2, {age: 18}]
let arr2 = deepClone(arr1)
arr2[2].age = 40
console.log(arr1) // 互不影响
console.log(arr2)

// 验证二:
let obj1 = {
  name: 'zhangsan',
  age: 30,
  study(){
    console.log(this.name)
  }
}
let obj2 = deepClone(obj1)

console.log(obj1) 
obj1.name = 'lisi'
console.log(obj1.study === obj2.study) // fasle


// 方式三:es9的方式
// Object.getOwnPropertyDescriptors
// 缺陷:只是做到了属性值的简单值的深拷贝,如果一个属性值是引用类型,只是浅拷贝
let obj1 = {
  name: 'zhangsan',
  age: 30,
  study(){
    console.log(this.name)
  }
}

const obj2 = {}
Object.defineProperties(obj2, Object.getOwnPropertyDescriptors(obj1))
obj2.age = 18
obj2.name = 'lisi'
console.log(obj1.age) // 30
console.log(obj2.age) // 18
console.log(obj1.study()) // zhangsan
console.log(obj2.study()) // lisi
console.log(obj1.study() === obj2.study()) // true

// 方式四:es10的方式
// 在es6的时候添加了spread操作符[...], 拆解、复制、合并等操作
// 在es9中,通过向对象文本添加扩展属性进一步扩展了这种语法,可以将一个对象的属性拷贝到另一个对象上。
// 缺陷:只是做到了属性值的简单值的深拷贝,如果一个属性值是引用类型,只是浅拷贝
let obj1 = {
  name: 'zhangsan',
  age: 30,
  study(){
    console.log(this.name)
  }
}

const obj2 = {...obj1}
obj2.age = 18
console.log(obj1.age) // 30
console.log(obj2.age) // 18
console.log(obj1.study === obj2.study) // true
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值