一、拷贝(克隆)的意义的场景
意义
:保证原数据的完整性和独立性
常见场景
:复制数据、函数入参、class构造函数
二、浅拷贝
- 只克隆对象的第一层级
- 如果属性值是原始数据类型,拷贝其值,即:值拷贝
- 如果属性值是引用类型,拷贝其内存地址,即:引用拷贝
1、ES6拓展运算符 … / slice(0) / [ ].concat
const sourceObject = { foo: [1, 2, 3], bar: { x: 10, y: 20 } };
const copiedObject = { ...sourceObject };
copiedObject.foo.push(4);
copiedObject.bar.z = 30;
console.log(sourceObject.foo); // Output: [1, 2, 3, 4] (原对象也被修改)
console.log(sourceObject.bar); // Output: { x: 10, y: 20, z: 30 } (原对象也被修改)
// 数组的浅拷贝
const arr = [1, 2, 3]
const arr2 = [...arr]
const arr3 = arr.slice(0)
const arr4 = [].concat(arr)
2、Object.assign()
const target = {};
const source1 = { foo: 1 };
const source2 = { bar: 2, aaa: {bbb: 666}};
Object.assign(target, source1, source2);
3、for…in…和其它的一层遍历复制
const source = { foo: 1, bar: 2 };
const target = {};
for (const key in source) {
target[key] = source[key];
}
console.log(target);
// Output: { foo: 1, bar: 2 }
const source = { foo: 1, bar: 2 };
const target = {};
for (const key in source) {
if (source.hasOwnProperty(key)) {
target[key] = source[key];
}
}
console.log(target);
// Output: { foo: 1, bar: 2 }
这样可以确保只复制对象自身的属性,而不包括继承的属性。
需要注意的是,for...in 循环不会复制对象的方法,只会复制属性。
如果要复制对象的方法,可以使用其他方法或库来实现更复杂的拷贝,比如深拷贝。
三、深拷贝
- 克隆对象的每个层级
- 如果属性值是原始数据类型,拷贝其值,即:值拷贝
- 如果属性值是引用类型,递归克隆
1、JSON.parse(JSON.stringify( obj ))
- 只能复制普通键的属性,Symbol类型的无能为力
- 循环引用对象,比如 window无法复制
- 函数 Date Rege Blob等类型不能复制
- 性能差
function clone(obj) {
return JSON.parse(JSON.stringify(obj))
}
const a = clone({
a: 1,
b: { c: 2 }
})
console.log('a:', a)
// 时间: 转为字符串
console.log('date:', clone({date:new Date()}))
// 正则: 变成空对象 异常
console.log('regex:', clone({regex:/[0-9]/}))
// Blob: 变成空对象 异常
console.log('blob:', clone({blob:new Blob(['123'])}))
// 函数
console.log('function:', clone({fn(){}})) // {}
// window
console.log('function:', clone(window)) // Uncaught TypeError: Converting circular structure to JSON
2、消息通讯BroadcastChannel
- 循环引用对象不能复制, 如 window
- 函数不能复制
- 同步变成异步
3、手写简单版深拷贝
上面的方法 如果在数组中添加了非数字属性就会出问题