引言:
在编程中,我们经常需要处理对象拷贝的场景。对象拷贝涉及到原对象和拷贝对象之间的关系,特别是在处理引用类型时需要格外注意。本文将深入探讨浅拷贝和深拷贝这两种常见的对象拷贝方式,包括它们的概念、区别以及适用场景。
一、浅拷贝
浅拷贝是指创建一个新对象,并将原对象中的属性值复制到新对象中。但需要注意的是,如果原对象的属性值是引用类型,浅拷贝只会复制引用,而不会复制实际的数据内容。这意味着原对象和拷贝对象之间共享同一份数据,对原对象的修改会影响到拷贝对象。
常见的浅拷贝方法有:
- Object.create(obj):通过创建一个新对象,并将原对象作为新对象的原型,实现浅拷贝。
// 原对象
let A = {
name : '小白',
hobby: {
n: '跑步'
}
}
// 使用Object.create() 进行浅拷贝
let copy = Object.create(A)
// 打印拷贝对象
console.log(copy.name, copy.hobby); // 小白 { n: '跑步' }
// 修改原对象
A.name = '小黑'
A.hobby.n = '跳舞'
console.log(A); // { name: '小黑', hobby: { n: '跳舞' } }
console.log(copy.name, copy.hobby); // 小黑 { n: '跳舞' }
// 通过打印结果,我们可以知道,原对象的修改会影响到拷贝对象
- Object.assign({}, obj):使用Object.assign()方法将原对象的属性复制到空对象中,实现浅拷贝。
// 还是上面那个对象
let copy = Object.assign({}, A)
console.log(copy); // { name: '小白', hobby: { n: '跑步' } }
// 修改原对象
A.name = '小黑'
A.hobby.n = '跳舞'
console.log(A); // { name: '小黑', hobby: { n: '跳舞' } }
console.log(copy); // { name: '小白', hobby: { n: '跳舞' } }
// 易知,虽然这个方法对于原始类型来说,原对象的修改不能影响拷贝对象,好像是深拷贝,但是对于引用类型来说,还是会受到影响,,所以还是浅拷贝
- [].concat(arr):通过连接原数组和空数组,生成一个新的数组,实现浅拷贝。
- 数组解构:使用数组解构语法[...arr]创建一个新的数组,并将原数组的元素复制到新数组中。
- arr.toReversed().reverse(),这段代码的意义是将一个数组进行反转,并再次进行反转,从而实现浅拷贝
// 3,4,5点实例
let arr = [1, 2, 3, {n: 10}]
let Arr1 = [].concat(arr)
let Arr2 = [...arr]
let Arr3 = arr.toReversed().reverse()
arr[3].n = 100
console.log(Arr1); // [ 1, 2, 3, { n: 100 } ]
console.log(Arr2); // [ 1, 2, 3, { n: 100 } ]
console.log(Arr3); // [ 1, 2, 3, { n: 100 } ]
// 对于属性为引用类型,这三个方法也只能拷贝引用,而不会拷贝里面的实际内容
二、深拷贝
深拷贝是指创建一个全新的对象,并递归地复制原对象的所有属性,包括嵌套的对象和数组。深拷贝后,新对象和原对象完全独立,互不影响。即使对原对象进行修改,也不会影响到拷贝对象。
常见的深拷贝方法是使用JSON.parse(JSON.stringify(obj))。这种方法通过将原对象转换为字符串,再将字符串转换回对象,实现深拷贝。
let obj = {
name: '小白',
age: 18,
a: {
n: 1
},
b: undefined,
c: null,
d: function() {},
e: Symbol('hello'),
}
let obj2 = JSON.parse(JSON.stringify(obj))
obj.a.n = 11
console.log(obj);
console.log(obj2);
// 打印结果:
{
name: '小白',
age: 18,
a: { n: 11 },
b: undefined,
c: null,
d: [Function: d],
e: Symbol(hello)
}
{ name: '小白', age: 18, a: { n: 1 }, c: null }
// 由结果知,虽然确实是深拷贝,但是有些数据类型却无法处理
需要注意该方法存在一些缺陷。首先,它无法处理特殊数据类型如undefined、function和Symbol。其次,当原对象存在循环引用时,即对象内部某个属性引用了对象自身,使用该方法会导致错误。
三、选择适当的拷贝方式 在实际开发中,我们需要根据具体需求来选择合适的拷贝方式。
浅拷贝适用于对简单对象进行拷贝,并且不关心原对象和拷贝对象之间的关联性。它具有简单、快速的特点,但需要注意对于引用类型属性的修改会影响到拷贝对象。
深拷贝适用于对复杂对象进行拷贝,并且希望实现原对象和拷贝对象之间的完全独立。它可以处理嵌套对象和数组,并确保对原对象的修改不会影响到拷贝对象。然而,需要注意深拷贝方法的局限性,特别是在处理特殊数据类型和循环引用时。
在实际应用中,如果需要更强大和灵活的拷贝功能,可以考虑使用第三方库,如lodash的_.cloneDeep()方法。这些库提供了更多选项以应对各种复杂情况。
结论: 对象拷贝是编程中常见的操作,浅拷贝和深拷贝是两种常用的拷贝方式。
浅拷贝只复制引用,对原对象的修改会影响到拷贝对象,适用于简单对象的拷贝。
深拷贝创建全新对象,递归复制所有属性,原对象和拷贝对象完全独立,适用于复杂对象的拷贝。但需要注意深拷贝方法可能存在的缺陷。
根据具体需求选择合适的拷贝方式,或者借助第三方库提供的更强大拷贝功能,可以更好地处理对象拷贝操作,提高代码的健壮性和可维护性。
感谢观看!