1、js对象的浅拷贝和深拷贝

对于基本数据类型而言, 不存在浅拷贝和深拷贝之分, 基本类型数据都是值类型,存储在栈内存中,每次赋值都是一次复制的过程。所谓浅拷贝深拷贝只是针对引用类型(对象)而言。

浅拷贝深拷贝具体解释如下:

  • 浅拷贝: 只是拷贝一层,更深层次对象级别的只拷贝了地址。
  • 深拷贝: 拷贝多层,即使是嵌套了对象,也会都拷贝出来,内容和原对象一样,更改原对象,拷贝对象不会发生变化。

在浅拷贝的时候如果数据是基本数据类型,那么就如同直接赋值那种,会拷贝其本身,如果除了基本数据类型之外还有一层对象,那么对于浅拷贝而言就只能拷贝其引用,对象的改变会反应到拷贝对象上。具体实例见2中的代码。

2、js对象浅拷贝

依次赋值

const obj = {
    a: {name: 'wyb'},
    b: 333
}
const newObj = {}
newObj.a=obj.a
newObj.b=obj.b

obj.a.name = 'update';
console.log(newObj);    // { a: { name: 'update' }, b: 333 }

for...in 遍历

const obj = {
  id: 1,
  name: "wyb",
  msg: {
    age: 25,
  },
};

const newObj = {};
for (const key in obj) {
  newObj[key] = obj[key];
}

obj.msg.age = 33;
console.log(newObj);    // { id: 1, name: 'wyb', msg: { age: 33 } }

Object.assign(目标对象,要拷贝的对象)

// ES6新增方法 assign可以快速实现浅拷贝
const obj = {
  id: 1,
  name: "wyb",
  msg: {
    age: 18,
  },
};

const newObj = {};
Object.assign(newObj, obj); // 把obj浅拷贝给newObj
obj.msg.age = 35;
console.log(newObj);    // { id: 1, name: 'wyb', msg: { age: 35 } }

3、js对象深拷贝

无脑方法

const obj = { name: "wyb", other: {age: 25} };
const newObj = JSON.parse(JSON.stringify(obj));
obj.other.age = 18;
console.log(obj);    // { name: 'wyb', other: { age: 18 } }
console.log(newObj); // { name: 'wyb', other: { age: 25 } }

注意这种方法不能转换function!

递归方法

完美的递归方法如下:

// 拷贝的目标: 数组、对象
const deepClone = (obj) => {
  const newObj = obj.constructor === Array ? [] : {};
  for (const key of Object.keys(obj)) {
    if (obj[key] && typeof obj[key] == "object") {
      newObj[key]= obj.constructor === Array ? [] : {};
      newObj[key] = deepClone(obj[key]);
    } else {
      newObj[key] = obj[key];
    }
  }
  return newObj;
};

const obj = {
  name: "wyb",
  age: 25,
  test: { desc: "Hello Word" },
};
const newObj = deepClone(obj);
obj.test.desc = "test";
console.log(obj); // { name: 'wyb', age: 25, test: { desc: 'test' } }
console.log(newObj); // { name: 'wyb', age: 25, test: { desc: 'Hello Word' } }

const arr = [
  "test",
  1,
  2,
  {
    name: "hello world",
  },
];
const newArr = deepClone(arr);
arr[3].name = "update";
console.log(arr);       // [ 'test', 1, 2, { name: 'update' } ]
console.log(newArr);    // [ 'test', 1, 2, { name: 'hello world' } ]

注意: newObj[key]= obj.constructor === Array ? [] : {};这一行代码本来是可以不用写的, 这里加上主要是为了起到提示作用(提高代码可维护性)。因为递归函数在刚刚开始的时候就判断了其应该返回的是[]还是{}, 这里写的并不会起作用, 后面newObj[key] = deepClone(obj[key]);执行后就自动覆盖了这行代码。