title: 手写深拷贝
categories: Javascript
tag:
- 手写深拷贝
date: 2021-11-30 23:05:34
深拷贝函数
前面我们已经学习了对象相互赋值的一些关系,分别包括:
- 引入的赋值:指向同一个对象,相互之间会影响;
- 对象的浅拷贝:只是浅层的拷贝,内部引入对象时,依然会相互影响;
- 对象的深拷贝:两个对象不再有任何关系,不会相互影响;
前面我们已经可以通过一种方法来实现深拷贝了:JSON.parse
- 这种深拷贝的方式其实对于函数、Symbol 等是无法处理的;
- 并且如果存在对象的循环引用,也会报错的;
自定义深拷贝函数:
- 自定义深拷贝的基本功能;
- 对 Symbol 的 key 进行处理;
- 其他数据类型的值进程处理:数组、函数、Symbol、Set、Map;
- 对循环引用的处理;
深拷贝的实现
function isObject(value) {
const valueType = typeof value
return value !== null && (valueType === 'object' || valueType === 'function')
}
function deepClone(originValue) {
// 判断传入的originValue是否是一个对象类型
if (!isObject(originValue)) {
return originValue
}
const newObj = {}
for (const key in originValue) {
newObj[key] = deepClone(originValue[key])
}
return newObj
}
//测试代码=============================================================
const obj = {
name: 'why',
age: 18,
friend: {
name: 'gwk',
address: {
city: '北京'
}
}
}
const newObj = deepClone(obj)
obj.friend.name = 'dh'
obj.friend.address.city = '杭州'
console.log(obj, newObj)
处理数组类型
可以看到以上代码。处理数组类型的时候
因此,我们需要判断这里的 obj 应该是对象还是数组。
修改为以下代码
处理函数类型
如果是函数类型,直接复用
处理 Symbol 类型
- Symbol 类型作为 value 的时候,拷贝的时候,会引用之前的。因此也需要对 Symbol 类型进行处理
- Symbol 类型为 key 的时候,我们发现是不能拷贝的。因为 Symbol 类型是不能遍历的。
处理 Set 类型
当我们的原始对象有 Set 数据类型的属性时
处理 Map 类型
和 Set 数据类型类似
此时经过以上处理,最终的深拷贝函数为:
function isObject(value) {
const valueType = typeof value
return value !== null && (valueType === 'object' || valueType === 'function')
}
function deepClone(originValue) {
//判断是否是Map类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
//判断是否是Set类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
// 判断如果是Symbol,就创建新的Symbol
if (typeof originValue === 'symbol') {
return Symbol(originValue.description)
}
//判断是否是函数
if (typeof originValue === 'function') {
// 判断传入的originValue是否是函数类型
return originValue
}
// 判断传入的originValue是否是一个对象类型
if (!isObject(originValue)) {
return originValue
}
const newObj = Array.isArray(originValue) ? [] : {}
for (const key in originValue) {
newObj[key] = deepClone(originValue[key])
}
// 对Symbol的key进行特殊处理
const symbolsKeys = Object.getOwnPropertySymbols(originValue)
for (const sKey of symbolsKeys) {
newObj[sKey] = deepClone(originValue[sKey])
}
return newObj
}
//测试代码========================================
let s1 = Symbol('aaa')
let s2 = Symbol('bbb')
const obj = {
name: 'why',
age: 18,
friend: {
name: 'gwk',
address: {
city: '北京'
}
},
hobby: ['篮球', '足球'],
foo: function () {
console.log('foo')
},
[s1]: 'aaa',
s2: s2,
set: new Set(['aaa', 'bbb', 'ccc']),
map: new Map([
['aaa', 'bbb'],
['bbb', 'ccc']
])
}
const newObj = deepClone(obj)
obj.friend.name = 'dh'
obj.friend.address.city = '杭州'
console.log(obj, newObj)
console.log(obj.s2 === newObj.s2)