手写一个深拷贝和浅拷贝

91 阅读2分钟

深拷贝和浅拷贝(超级详细,有内存图)

首先,浅拷贝和深拷贝都是只针对于像Object,Array这样的复杂对象。

区别:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制

一、手写一个浅拷贝方法和深拷贝方法

//浅拷贝
function shallowClone(target) {
  let cloneTarget = {};
  for (const key in target) {
    cloneTarget[key] = target[key];
  }
  return cloneTarget;
}
//深拷贝
function deepClone(target) {
  if (typeof target === 'object') { // 是对象的话要进行深拷贝
    let cloneTarget = {};
    for (const key in target) {
      cloneTarget[key] = deepClone(target[key]); //递归
    }
    return cloneTarget;
  } else {   //普通值/函数不需要深拷贝
    return target;
  }
}

二、浅拷贝的实现方法[obj为普通对象,copyObj为复制后的新对象]

1)Object.assign()对象合并
let copyObj = Obiect.assign({},obj)
//花括号里叫目标对象,obj为源对象

📢 Object.assign()方法属于es6中新增的对象的扩展

2)函数库lodash的_.clone方法
var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.clone(obj1);
console.log(obj1.b.f === obj2.b.f);// true
3)展开运算符
  • 通过展开运算符 ... 来实现浅拷贝
  • 展开运算符是一个 es6 / es2015特性,它提供了一种非常方便的方式来执行浅拷贝,这与Object.assign ()的功能相同。
  • 如果只是一层数组或对象,其元素只是简单类型的元素,那么这一层就不是浅拷贝!!(就是一层拷贝,你可以理解为深拷贝,但并不是深拷贝)
  • 如果数组或对象中的元素是引用类型的元素,那么就是浅拷贝
let obj = { name: 'youzi', address:{x:100,y:100}}
let copyObj= {... obj1}
obj.address.x = 200;
obj.name = 'heyunchen'  //此时copyObj的属性仍然是youzi,因为这一层不是引用类型的拷贝
console.log('copyObj',copyObj) //copyObj { name: 'youzi', address: { x: 200, y: 100 } }
4)Array.prototype.concat()或者 Array.prototype.slice()
  • Array.concat(arr1,arr2…),合并两个或多个数组,生成一个新的数组。原数组不变。
  • Array.slice() 按照条件查找出其中的部分内容
  • 利用数组API,这两个都返回新数组,当数组中嵌套数组对象时为浅拷贝
  • 数组对象:数组中含对象
let arr = [1, 3, {
    username: 'kobe'
    }];
let arr2 = arr.concat();
//let arr3 = arr.slice();
arr2[2].username = 'wade';
//arr3[2].username = 'wade';
console.log(arr); //[ 1, 3, { username: 'wade' } ]

三、深拷贝的实现

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

这是利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE

JSON.stringify() JSON.parse()

2)函数库lodash的_.cloneDeep方法
var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
3)jQuery.extend()方法
$.extend(deepCopy,target,obj1,[objN]) // 第一个参数为true就是深拷贝