深拷贝与浅拷贝

124 阅读2分钟

「这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战」。

怎样实现深拷贝和浅拷贝?

js中有两种数据类型,一种是基本数据类型,一种是引用数据类型,基本数据类型是按值访问的,而引用数据类型的值是按引用。浅拷贝,就是只要改变其中一个对象的值另外一个就是一起改变;深拷贝,会开辟一个新的内存地址来存放新对象的值,两个对象对应不同的内存地址,修改一个对象并不会对另外一个对象产生影响。

实现浅拷贝:

  1. Object.assign(),返回目标对象,但其拷贝的是属性值,假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值

    var a = {a : 'old', b : { c : 'old'}}
    var b = Object.assign({}, a)
    b.a = 'new'
    b.b.c = 'new'
    console.log(a) // { a: 'old', b: { c: 'new' } }
    console.log(b) // { a: 'new', b: { c: 'new' } }2
    //当拷贝的源对象的属性值是一个对象时,拷贝的只是对象的引用值,因此当修改属性值的时候两个对象的属性值都会发生更新
    
  2. 自己如何简单实现一个浅拷贝呢?

    function copy(obj) {
      if (!obj || typeof obj !== 'object') {
        return
      }
    ​
      var newObj = obj.constructor === Array ? [] : {}
      for (var key in obj) {
        newObj[key] = obj[key]
      }
    }
    var a = {b: 'bb', c: 'cc',  d: {e: 'ee'}}
    var b = copy(a)
    console.log(b) // { b: 'bb', c: 'cc', d: { e: 'ee' } }
    

实现深拷贝:

  1. 利用JSON.stringfy()和JSON.parse()搭配使用,先转换成字符串,在转换程新的对象,弊端在JSON.stringify()做序列时,undefined、任意的函数以及symbol值,在序列化过程中会被忽略,导致拷贝生成的对象中没有对应属性及属性值
    var obj = {a: {b: 'old'}, c:undefined, d: function () {}, e:  Symbol('')}
    var newObj = JSON.parse(JSON.stringify(obj))
    newObj.a.b = 'new'
    console.log(obj) // { a: { b: 'old' }, c: undefined, d: [Function: d], e: Symbol() }
    console.log(newObj) // { a: { b: 'new' } }
  1. 通过递归,通过对需要拷贝的对象的属性进行递归遍历,如果对象的属性不是基本类型时,就继续递归,知道遍历到对象属性为基本类型,然后将属性和属性值赋给新对象。
function copy(obj) {
  if (!obj || typeof obj !== 'object') {
    return
  }
  var newObj = obj.constructor === Array ? [] : {}
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === 'object' && obj[key]) {
        newObj[key] = copy(obj[key])//是否为引用类型,是的话就递归
      } else {
        newObj[key] = obj[key]//基本类型就直接赋值
      }
    }
  }
  return newObj
}

var old = {a: 'old', b: {c: 'old'}}
var newObj = copy(old)
newObj.b.c = 'new'
console.log(old) // { a: 'old', b: { c: 'old' } }
console.log(newObj) // { a: 'old', b: { c: 'new' } }