下面一篇文章我们来实现一下深拷贝。
深拷贝的介绍
通过定义的方法,拷贝出的对象和原来的对象没有关系。修改任何对象都不会相互影响。
通过JSON方法来处理深拷贝
const info = JSON.parse(JSON.stringify(obj))
存在的问题:
- 对于函数、Symbol等是无法处理的
- 存在对象的循环引用,也会报错的
自定义深拷贝函数
- 基本封装
- 他只能处理基本数据类型, 对象, 数组。
- 不能处理Symbol, Function, 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 newObject = Array.isArray(originValue) ? []: {}
for (const key in originValue) { // 如果originValue是一个函数(其实任何值都不会报错)in操作符也不会报错。
newObject[key] = deepClone(originValue[key])
}
return newObject
}
- 处理函数类型。
// 判断如果是函数类型, 那么直接使用同一个函数
if (typeof originValue === "function") {
return originValue
}
- 处理Symbol类型
- Symbol作为值是可以直接拷贝的。
- 由于for ... of不能遍历Symbol为key的对象,所以需要做特殊处理。
// 判断如果是Symbol的value, 那么创建一个新的Symbol
if (typeof originValue === "symbol") {
return Symbol(originValue.description)
}
// 对Symbol的key进行特殊的处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const sKey of symbolKeys) {
newObject[sKey] = deepClone(originValue[sKey])
}
- 处理Set, Map类型
- 注意: 这里只对Set,Map类型做浅拷贝。
// 判断是否是一个Set类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
// 判断是否是一个Map类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
- 处理对象循环引用问题
- 通过Map来实现,就是先把对象放进Map中。每次遍历,如果遇到循环引用,那么直接将newObject赋值给他。
- 并且为了防止多次调用,自由变量Map中的值过多,应该将Map作为参数传递。
function isObject(value) {
const valueType = typeof value
return (value !== null) && (valueType === "object" || valueType === "function")
}
function deepClone(originValue, map = new WeakMap()) {
// 判断是否是一个Set类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
// 判断是否是一个Map类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
// 判断如果是Symbol的value, 那么创建一个新的Symbol
if (typeof originValue === "symbol") {
return Symbol(originValue.description)
}
// 判断如果是函数类型, 那么直接使用同一个函数
if (typeof originValue === "function") {
return originValue
}
// 判断传入的originValue是否是一个对象类型
if (!isObject(originValue)) {
return originValue
}
if (map.has(originValue)) {
return map.get(originValue)
}
// 判断传入的对象是数组, 还是对象
const newObject = Array.isArray(originValue) ? []: {}
map.set(originValue, newObject)
for (const key in originValue) {
newObject[key] = deepClone(originValue[key], map)
}
// 对Symbol的key进行特殊的处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const sKey of symbolKeys) {
// const newSKey = Symbol(sKey.description)
newObject[sKey] = deepClone(originValue[sKey], map)
}
return newObject
}
xdm, 你不容错过的JavaScript高级语法专栏已经更文完毕,感谢大家的观看。