所谓克隆就是复制,正常来说,复制出来的不应该会影响原来的,但事实并非如此,从而有了深浅克隆之分。直接上代码论(方便大家方便看,所以截图这块)
可以看到:浅克隆只是克隆了第一层,cloneObj和 obj中的 o对象仍然是指向同一个堆内存,因此,对cloneObj.o.x赋新值时, obj.o.x的值也随之改变。
如果是深克隆 无论cloneObj怎么改变,都不会影响obj的值
除了利用扩展运算符实现浅克隆,还有:
Object.assign()
const obj1 = {a: 1, b: 2}
const obj2 = Object.assign({}, obj1)
for...in
let obj1 = {
name: "bob",
age: 18,
sex: "man",
o: { x: 1 }
}
let obj2 = {}
for(let key in obj1){
// fon..in会遍历原型上的方法,因此要阻止遍历原型
if(!obj1.hasOwnProperty(key)) break;
// 将 obj1 的所有属性遍历并赋值给 obj2
obj2[key] = obj1[key]
}
Object.keys()
let obj1 = {
name: "bob",
age: 18,
sex: "man",
o: { x: 1 }
}
let obj2 = {}
// 与for...in 不同的是,Object.keys()不会遍历原型上的方法
for (let key Object.keys(obj1) {
obj2[key] = obj1[key]
}
实现深克隆
如果对象中的属性值不是函数、undefined以及symbol值等
一般使用JSON.stringify 和 JSON.parse 简单粗暴
let obj1 = {
name: "bob",
age: 18,
sex: "man",
o: { x: 1 }
}
let obj2 = JSON.parse(JSON.stringify(obj1))
obj2.o.x = 2
console.log(obj1.o.x) // 不受Obj2的影响,仍然是 1
当然,要实现特殊值的深克隆,需要特殊处理
递归方法实现深克隆
const cloneDeep = (target, hash = new WeakMap()) => {
// 如果是基本类型直接返回
if(typeof target !== 'object' || target === null) {
return target
}
// 如果是正则
if(target instanceof RegExp) {
return new RegExp(target)
}
// 如果是时间对象
if (target instanceof Date) {
return new Date(target)
}
// 哈希表中存在直接返回
if (hash.has(target)) return hash.get(target)
const cloneTarget = Array.isArray(target) ? [] : {}
hash.set(target, cloneTarget)
// 对Symbol属性处理
const symKeys = Object.getOwnPropertySymbols(target)
if (symKeys.length) {
symKeys.forEach(sk => {
// 处理symbol的值为对象且非空对象
if (typeof target[sk] === 'object' && target[sk] !== null) {
cloneTarget[sk] = cloneDeep(target[sk])
} else {
cloneTarget[sk] = target[sk]
}
})
}
// 遍历target, 且不遍历原型上的属性(使用ES6的方法,不使用for...in)
for (let key of Object.keys(target)) {
cloneTarget[key] = typeof target[key] === 'object' && target[key] !== null
? cloneDeep(target[key], hash) : target[key]
}
return cloneTarget
}
验证:
可以看到,深克隆已实现,并且克隆对象clone改变并不会影响 原对象obj