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]);
执行后就自动覆盖了这行代码。