浅拷贝
对象的浅拷贝
Object.assign()
使用 Object.assign()。该函数会拷贝assign()的第二个参数,比如下例中,我们会拷贝第二个参数(也就是obj1)。
const obj1 = { a: 1, b: 2 };
const obj2 = Object.assign({}, obj1);
console.log(obj2); // { a: 1, b: 2 }
展开运算符
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1 };
console.log(obj2); // { a: 1, b: 2 }
for...in循环遍历拷贝
注意,for...in 会遍历对象自身的属性,以及原型链上的属性。因此,需要通过 hasOwnProperty 判断该属性是否是自身属性。
const obj1 = { a: 1, b: 2, c: { d: 4 } };
const obj2 = {};
for (const key in obj1) {
if (obj1.hasOwnProperty(key)) {
obj2[key] = obj1[key];
}
}
console.log(obj2); // { a: 1, b: 2, c: { d: 4 } }
Object.keys()循环遍历拷贝
Object.keys() 只会遍历自身属性,而不会遍历原型链上的属性。
const obj1 = { a: 1, b: 2, c: { d: 4 } };
const obj2 = {};
Object.keys(obj1).forEach(key => {
obj2[key] = obj1[key];
});
console.log(obj2); // { a: 1, b: 2, c: { d: 4 } }
数组的浅拷贝
通过 slice() 方法拷贝
const arr1 = [1, 2, 3];
const arr2 = arr1.slice();
console.log(arr2); // [1, 2, 3]
通过 concat() 方法拷贝
const arr1 = [1, 2, 3];
const arr2 = [].concat(arr1);
console.log(arr2); // [1, 2, 3]
深拷贝
JSON.parse(JSON.stringify(obj))
它既可以拷贝对象,也可以拷贝数组。但是,在以下场景中不能使用它。
1.无法拷贝函数
由于 obj 的 b 属性是一个函数,JSON在序列化的时候,会忽略函数,因此无法拷贝 b 属性。
const obj = {
a: 1,
b: function () {
console.log('hello');
},
};
const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj); // { a: 1 }
2.无法拷贝特殊对象,如 Date 、正则表达式
const obj = {
date: new Date(),
regex: /test/,
};
const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj.date); // 输出字符串,而不是 Date 对象
console.log(newObj.regex); // 输出空对象,而不是 RegExp 对象
3. 不会拷贝原型链上的属性
c 是原型链上的属性,但拷贝后的到的新对象 newObj 上没有 c 属性。
const protoObj = { c: 3 };
const obj = Object.create(protoObj);
obj.a = 1;
obj.b = 2;
const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj.c); // undefined
4. 会忽略 symbol 和 undefined 属性
const obj = {
a: undefined,
b: Symbol('test'),
};
const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj); // 输出空对象:{}
手写一个简单的深拷贝
function deepClone(obj) {
// 基本数据类型直接返回
if (typeof obj !== 'object' || obj === null) {
return obj;
}
// 根据输入对象的类型创建一个新的对象或数组
let clone = Array.isArray(obj) ? [] : {};
// 遍历对象的属性,并递归进行深拷贝
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key]);
}
}
return clone;
}
// 示例
const obj = {
a: 1,
b: [2, 3, { d: 4 }],
c: {
e: 5
}
};
const clonedObj = deepClone(obj);
console.log(clonedObj); // 输出 { a: 1, b: [2, 3, { d: 4 }], c: { e: 5 } }
console.log(clonedObj !== obj); // 输出 true