对象浅拷贝和深拷贝的拷贝方法

如果要拷贝的对象里面没有object或者array这种复杂的类型属性,那么就使用浅拷贝。如果想完整复制一个对象,对象里有object或者array这种复杂的类型属性,且想要复制的对象和原对象互不影响,就使用深拷贝。

浅拷贝:

JavaScript 中,数组有两个方法 concat 和 slice 是可以实现对原数组的拷贝的。同时,ES6 中 引入了 Object.assgn 方法和 ... 扩展运算符也能实现对对象的拷贝。

let arr1 = [1, 2, 3, 4, { name: 'Mary' }];
// 浅拷贝
const arr2 = arr1.concat();
const arr3 = arr1.slice(0);
const arr4 = [...arr1];
// 操作
arr1.push(6);
arr1[4].name = 'Jack';
console.log(arr1); // [ 1, 2, 3, 4, { name: 'Jack' }, 6 ]
console.log(arr2); // [ 1, 2, 3, 4, { name: 'Jack' } ]
let obj1 = { a:1, b:'b', c:{ name: 'Mary' }};
// 浅拷贝
const obj2 = { ...obj1 };
const obj3 = Object.assign({}, obj1);
// 操作
obj1.a = 2;
obj1.b = 'newB';
obj1.c.name = 'June';
console.log(obj1); // { a: 2, b: 'newB', c: { name: 'June' } }
console.log(obj2); // { a: 1, b: 'b', c: { name: 'June' } }

深拷贝:

可以通过递归一层层拷贝。

function deepCopy(obj, appeard = new Map()) {
  if (!(obj instanceof Object)) return obj; // 如果是原始数据类型
  if (appeard.has(obj)) return appeard.get(obj); // 如果已经出现过
  const result = Array.isArray(obj) ? [] : {};
  appeard.set(obj, result); // 将新对象放入map
  // 遍历所有属性进行递归拷贝
  [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)]
    .forEach(key => {
      result[key] = deepCopy(obj[key], appeard);
    });
  return result;
}

或者通过JSON转化。JSON转化的优缺点:

优点:可以处理纯对象的深拷贝

缺点:

  1. 如果对象里有函数,函数无法被拷贝下来(RegExp/函数不会拷贝)
  2. 无法拷贝old对象原型链上的属性和方法
  3. 当数据的层次很深,会栈溢出
  4. undefined,NaN, -Infinity, Infinity 都会被转化成null
  5. new Date()会被转成字符串
const newObj = JSON.parse(JSON.stringify(old));

深拷贝的效果:

let obj1 = { a:1, b:'b', c:{ name: 'Mary' }};
const obj2 = deepCopy(obj1);
// 操作
obj1.c.name = 'Anna';
console.log(obj1); // { a: 1, b: 'b', c: { name: 'Anna' } }
console.log(obj2); // { a: 1, b: 'b', c: { name: 'Mary' } }

 

posted @ 2021-12-08 09:38  远看山有色  阅读(362)  评论(0)    收藏  举报