下面我将详细讲解JS中不一样的深拷贝的完整攻略。
什么是深拷贝
深拷贝是指将一个对象完整复制一份并生成一个新对象,新对象和旧对象互不影响,即使新对象被修改了,旧对象也不会发生改变。
JavaScript 中的深拷贝
在 JavaScript 中,拷贝对象的方法是 Object.assign()
或者使用扩展运算符 ...
。然而,这些拷贝方法都只能进行浅拷贝。
浅拷贝只是复制了对象的第一层级属性,如果是一个嵌套的对象就会出现问题。比如一个对象的属性值是一个引用类型,那么浅拷贝会复制这个引用类型的内存地址,新旧对象的这一属性的值就会指向同一个内存地址。
因此,如果要进行深拷贝,需要使用其他方法或者手动实现深拷贝的方法。下面介绍两种比较常见的深拷贝方式。
JSON.parse(JSON.stringify(obj))
使用 JSON.parse(JSON.stringify(obj)) 可以实现深拷贝。它的原理是利用 JSON.stringify() 将原对象序列化成一个 JSON 字符串,再利用 JSON.parse() 将这个 JSON 字符串解析成一个新的对象,这个新的对象与原对象没有任何的引用关系。
但是,这个方法是有限制的,它只能序列化那些 JSON 能够表示的数据类型,而不能序列化那些不能被表示为 JSON 的数据类型,比如 undefined 和 function。
代码示例:
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj))
}
let oldObj = {name: '张三', age: 18, info: {hobby: 'basketball'}}
let newObj = deepCopy(oldObj)
console.log(oldObj.age) // 18
console.log(newObj.age) // 18
oldObj.age = 20
console.log(oldObj.age) // 20
console.log(newObj.age) // 18
oldObj.info.hobby = 'football'
console.log(oldObj.info.hobby) // football
console.log(newObj.info.hobby) // basketball
可以看到,使用这种方式进行深拷贝,无法复制原始对象中的引用类型,修改原始对象的引用类型会影响复制后的引用类型。
递归实现
另外一种方法是手动实现递归拷贝,递归遍历对象,复制对象的每一个属性,直到遍历到属性值为基本类型时结束递归。
代码示例:
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') {
return obj
}
let newObj = Array.isArray(obj) ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepCopy(obj[key])
}
}
return newObj
}
let oldObj = {name: '张三', age: 18, info: {hobby: 'basketball'}}
let newObj = deepCopy(oldObj)
console.log(oldObj.age) // 18
console.log(newObj.age) // 18
oldObj.age = 20
console.log(oldObj.age) // 20
console.log(newObj.age) // 18
oldObj.info.hobby = 'football'
console.log(oldObj.info.hobby) // football
console.log(newObj.info.hobby) // basketball
可以看到,使用递归实现深拷贝,能够完整复制原始对象中的引用类型,修改原始对象的引用类型不会影响复制后的引用类型。
总结
以上两种方法都可以实现深拷贝,但是第一种方法是将原始对象序列化成字符串,然后又通过解析字符串生成一个新的对象,可能会带来额外的性能开销。而第二种方法是完全手写,需要自己实现递归遍历,并创建新的对象,相对而言比较繁琐。需要根据自己的实际业务需求选择适合的深拷贝实现方式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详细聊聊JS中不一样的深拷贝 - Python技术站