下面一篇文章我们来实现一下深拷贝。
深拷贝的介绍
通过定义的方法,拷贝出的对象和原来的对象没有关系。修改任何对象都不会相互影响。
通过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 }