浅拷贝与深拷贝

82 阅读3分钟

浅拷贝

  • 浅拷贝的意思就是只复制引用,而未复制真正的值。
const fruitsObj = {
  apple:'12个',
  banana:'10个',
  orange:{
    big:'10个',
    little:'20个'
  },
}
// 浅拷贝方法
const  shallowClone = originObj=> {
  var targetObj = {};
  for(let key in originObj) {
      if (originObj.hasOwnProperty(key)) {
        targetObj[key] = originObj[key];
      }
  }
  return targetObj;
}
const _fruitsObj = shallowClone(fruitsObj) // 浅拷贝
console.log(_fruitsObj===fruitsObj,'..._fruitsObj===fruitsObj')  // false
_fruitsObj.apple='22个' // 第一层,原对象第一层没有改变
_fruitsObj.orange.big='5个' // 第二层,原对象第二层改变了

深拷贝

  • 目前实现深拷贝的方法不多,主要是两种:
    • 利用 JSON 对象中的 parse 和 stringify --- 性能最快
    • 利用递归来实现每一层都重新创建对象并赋值

1. JSON.parse(JSON.stringify())**

const animalObj = {
  birds:['chicken','duck'],
  lactation:['dog','cat'],
}
const _animalObj =JSON.parse(JSON.stringify(animalObj))  // 深拷贝
console.log(_animalObj===animalObj) // false
_animalObj.lactation=['pig']   // 修改_animalObj中lactation的值
console.log(_animalObj,animalObj) // _animalObj更改了,animalObj没有更改
  • JSON.parse(JSON.stringify())很好用但是,但是有些情况不能使用
    • 具有循环引用的对象时,报错
    • 当值为函数、undefined、或symbol时,无法拷贝

2. 利用递归来实现每一层都重新创建对象并赋值**

function deepClone(originObj){
  const targetObj = originObj.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
  for(let keys in originObj){ // 遍历目标
    if(originObj.hasOwnProperty(keys)){       // // hasOwnProperty判断是否为自身属性
      if(originObj[keys] && typeof originObj[keys] === 'object'){ // 如果值是对象,就递归一下
        targetObj[keys] = originObj[keys].constructor === Array ? [] : {}
        targetObj[keys] = deepClone(originObj[keys]);
      }else{ // 如果不是,就直接赋值
        targetObj[keys] = originObj[keys]
      }
    }
  }
  return targetObj
}
const PetsObj = {
  cat:'猫咪',
  pig:['小猪佩奇','乔治'],
  dog:{
    1:'柯基',
    2:'藏獒'
  },
  snake:()=>{
    console.log('一条蓝色的小蛇')
  },
  cow:undefined,
  sheep:Symbol()
}
const _PetsObj = deepClone(PetsObj)
console.log(_PetsObj===PetsObj) //false
_PetsObj.pig='小猪佩奇'
console.log(_PetsObj,PetsObj) // PetsObj没有更改

如何实现浅拷贝

1、concat(value)

const obj1 = ['a',{b:'c'},'d']
const _obj1 = [].concat(obj1)
console.log(_obj1===obj1)  // false
_obj1[0]='aaa'
_obj1[1].b='ccc'
console.log(obj1) // ['a',{b:'ccc'},'d'] 

2、value.slice()

const obj2 = ['a',{b:'c'},'d']
const _obj2 = obj2.slice()
console.log(obj2===_obj2) // false
_obj2[0]='aaa'
_obj2[1].b='ccc'
console.log(obj2) // ['a',{b:'ccc'},'d'] 

3、Object.assign(value)

const obj3 = {
  a:'1',
  b:{
    c:1
  }
}
const _obj3 = Object.assign(obj3)
console.log(obj3===_obj3,'....obj3===_obj3') // true
_obj3.a = '111'   // 第一层
_obj3.b.c = {d:'123'}  // 第二层
console.log(obj3) // {a:'111',b:{c:{d:'123'}}}  // 都更改了

4、展开运算符... 实现的是对象第一层的深拷贝

const obj4 = {
  a:'1',
  b:{
    c:1
  }
}
const _obj4 = {...obj4}
console.log(_obj4===obj4) // false
_obj4.a = '111'   // 第一层
_obj4.b.c = {d:'123'}  // 第二层
console.log(obj4)   // {a:'1',b:{c:{d:'123'}}}

5、lodash中的_.clone(value)

var _ = require('lodash');
const obj5 = {
    a: '1',
    b: {
      c: 1,
    },
  }
const _obj5 = _.clone(obj5)
console.log(_obj5 === obj5) // false
_obj5.a = '111' // 第一层
_obj5.b.c = {d: '123'} // 第二层
console.log(obj5) // {a:'1',b:{c:{d:'123'}}}

如何实现深拷贝

1、JSON.parse(JSON.stringfy(value))

const animalObj = {
  birds:['chicken','duck'],
  lactation:['dog','cat'],
}
const _animalObj =JSON.parse(JSON.stringify(animalObj))  // 深拷贝
console.log(_animalObj===animalObj) // false
_animalObj.lactation=['pig']   // 修改_animalObj中lactation的值
console.log(_animalObj,animalObj) // _animalObj更改了,animalObj没有更改

2、lodash中的_.cloneDeep(value)

var _ = require('lodash');
const obj6 = {
      a: '1',
      b: {
        c: 1,
      },
    }
const _obj6 = _.cloneDeep(obj6)
console.log(_obj6 === obj6) // false
_obj6.a = '111' // 第一层
_obj6.b.c = {d: '123'} // 第二层
console.log(obj6) // {a:'1',b:{c:1}}

3、手写递归

function deepClone(originObj){
  const targetObj = originObj.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
  for(let keys in originObj){ // 遍历目标
    if(originObj.hasOwnProperty(keys)){       // // hasOwnProperty判断是否为自身属性
      if(originObj[keys] && typeof originObj[keys] === 'object'){ // 如果值是对象,就递归一下
        targetObj[keys] = originObj[keys].constructor === Array ? [] : {}
        targetObj[keys] = deepClone(originObj[keys]);
      }else{ // 如果不是,就直接赋值
        targetObj[keys] = originObj[keys]
      }
    }
  }
  return targetObj
}

本文使用 mdnice 排版