返回
Javascript 克隆的那些事
前端
2024-02-15 12:53:14
Javascript 中的克隆(拷贝)是一个非常重要的操作,而且我们经常会用到它。克隆就是将一个对象里的属性、方法等复制到另一个对象中,而且互不影响(即克隆之后,对一个对象进行修改,不会影响到另一个对象)。今天我们就来讨论一下原生 Javascript 中克隆的问题。
我们现在想把 obj 里面的每一个属性拷贝到一个空对象 v 中:
const obj = {
name: 'John',
age: 30,
};
const v = {};
for (const key in obj) {
v[key] = obj[key];
}
console.log(v); // {name: 'John', age: 30}
这样就可以实现克隆了,但是这种方法存在一个问题:它不能克隆对象中的嵌套对象或数组。如果 obj 中有一个嵌套对象,那么 v 中的对应属性将是一个指向原始嵌套对象的引用,而不是它的副本。
const obj = {
name: 'John',
age: 30,
address: {
street: 'Main Street',
number: 123,
},
};
const v = {};
for (const key in obj) {
v[key] = obj[key];
}
console.log(v); // {name: 'John', age: 30, address: {street: 'Main Street', number: 123}}
v.address.street = 'New Street';
console.log(obj); // {name: 'John', age: 30, address: {street: 'New Street', number: 123}}
正如你所看到的,当我们修改 v.address.street 时,obj.address.street 也随之改变了。这是因为 v.address 指向的是 obj.address 的同一个引用。
为了解决这个问题,我们需要使用递归克隆。递归克隆会遍历对象中的每个属性,如果该属性是一个对象或数组,则会递归地克隆它。
const deepClone = (obj) => {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(deepClone);
}
const clonedObj = {};
for (const key in obj) {
clonedObj[key] = deepClone(obj[key]);
}
return clonedObj;
};
使用递归克隆,我们可以正确地克隆嵌套对象和数组:
const obj = {
name: 'John',
age: 30,
address: {
street: 'Main Street',
number: 123,
},
};
const v = deepClone(obj);
console.log(v); // {name: 'John', age: 30, address: {street: 'Main Street', number: 123}}
v.address.street = 'New Street';
console.log(obj); // {name: 'John', age: 30, address: {street: 'Main Street', number: 123}}
现在,当我们修改 v.address.street 时,obj.address.street 不会改变,因为它们是两个不同的对象。
希望本文能帮助你理解 Javascript 中的克隆问题。如果你有任何疑问,请随时留言。