前言
想要理解深拷贝与浅拷贝并运用到实战当中,需要对JS的数据类型了如指掌,如果说你还不会的话,建议移步至我的另一篇博客《高手带你通透JS的数据类型》,学完后会更好理解。
浅拷贝
浅拷贝的含义就是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。简单来说就是只拷贝了数据对象的第一层,深层次的数据值与原始数据会互相影响。
常见的浅拷贝的方法有:Object.assign(),展开运算符
下面请看示例:
const obj1 = { name: 'dog', info: { age: 3 } }
const obj2 = Object.assign({}, obj1)
// 或者
const obj2 = { ...obj1 }
obj2.name = 'cat'
obj2.info.age = 4
console.log(obj1) // { name: 'dog', info: { age: 4 } }
console.log(obj2) // { name: 'cat', info: { age: 4 } }
当拷贝后的对象obj2
数据改变的时候会影响原始数据obj1
,因为info
对象拷贝的是源对象指针。
深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响,不管数据有多少层,改变拷贝后的值都不会影响原始数据。
常见深拷贝的方法有:JSON.parse()和JSON.stringify()配合使用
下面请看示例:
const obj1 = { name: 'dog', info: { age: 3 }, fn: function () {} }
const obj2 = JSON.parse(JSON.stringify(obj1))
obj2.name = 'cat'
obj2.info.age = 4
console.log(obj1) // { name: 'dog', info: { age: 3 }, fn: function(){} }
console.log(obj2) // { name: 'cat', info: { age: 4 } }
这种方式有一个弊端,就是无法正确处理函数和正则。
我们也可以手写一个深拷贝的方法(简易基础版)。
function deepClone(source) {
// null数据需要特殊处理
if (source === null) {
return source
}
// 校验要拷贝的数据是对象还是数组
const target = Array.isArray(source) ? [] : {}
for (const k in source) {
const val = source[k]
const valueType = typeof val
// 校验拷贝的数据类型
if (valueType === 'function') {
target[k] = new Function(`return ${val.toString()}`)()
} else if (valueType === 'object') {
target[k] = deepClone(val)
} else {
target[k] = val
}
}
return target
}
const obj1 = { name: 'dog', info: { age: 3 }, fn: function () {} }
const obj2 = deepClone(obj1)
obj2.name = 'cat'
obj2.info.age = 4
console.log(obj1) // { name: 'dog', info: { age: 3 }, fn: function(){} }
console.log(obj2) // { name: 'cat', info: { age: 4 }, fn: function(){} }