78.实现一个深拷贝
webVueBlog opened this issue · 0 comments
webVueBlog commented
实现一个深拷贝
function myDeepCopy (obj, map = new WeakMap()) {
if (typeof obj !== 'object') return;
if (obj instanceof Date) {
const copyDate = new Date();
copyDate.setTime(obj.getTime());
return copyDate;
}
if (obj instanceof RegExp) {
const Constructor = obj.constructor;
return new Constructor(obj);
}
let newObj = obj instanceof Array ? [] : {};
if (map.get(obj)) {
return map.get(obj);
}
map.set(obj, newObj);
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] =
obj[key] instanceof Object ? myDeepCopy(obj[key], map) : obj[key];
}
}
return newObj;
}
const mapTag = '[object Map]'
const setTag = '[object Set]'
const arrayTag = '[object Array]'
const objectTag = '[object Object]'
const argsTag = '[object Arguments]'
const boolTag = '[object Boolean]'
const dateTag = '[object Date]'
const numberTag = '[object Number]'
const stringTag = '[object String]'
const symbolTag = '[object Symbol]'
const errorTag = '[object Error]'
const regexTag = '[object RegExp]'
const funcTag = '[object Function]'
const deepTags = [
mapTag,
setTag,
arrayTag,
objectTag,
boolTag,
boolTag,
dateTag,
numberTag,
stringTag,
symbolTag,
errorTag,
regexTag,
funcTag,
]
function forEach(array, iteratee) {
let index = -1;
const { length } = array
while (++index < length) {
iteratee(array[index], index)
}
return array
}
function isObject(target) {
const type = typeof target
return target && (type === 'object' || type === 'function')
}
function getType(target) {
return Object.prototype.toString.call(target)
}
function getInit(target) {
const Ctor = target.constructor
return new Ctor()
}
function cloneSymbol(target) {
return Object(Symbol.prototype.valueOf.call(target))
}
function cloneReg(target) {
const reFlags = /\w*$/
const result = new target.constructor(target.source, reFlags.exec(target);
result.lastIndex = target.lastIndex
return result
)
function cloneFunction(func) {
const bodyReg = /(?<={)(.|\n)+(?=})/m
const paramReg = /(?<=\().+(?=\)\s+{)/
const funcString = func.toString()
if (func.prototype) {
const param = paramReg.exec(funcString)
const body = bodyReg.exec(funcString)
if (body) {
if (param) {
const paramArr = param[0].split(',')
return new Function(...paramArr, body[0])
}
return new Function(body[0])
}
return null
}
return eval(funcString)
}
function cloneOtherType(target, type) {
const Ctor = target.constructor
switch (type) {
case boolTag:
case numberTag:
case stringTag:
case errorTag:
case dateTag:
return new Ctor(target)
case regexTag:
return new cloneReg(target)
case symbolTag:
return cloneFunction(target)
case funcTag:
return cloneFunction(target)
default:
return null
}
}
function clone(target, map = new WeakMath()) {
// 克隆原始类型
if (!isObject(target)) return target
// 初始化
const type = getType(target)
let cloneTarget
if(deepTag.includes(type)) cloneTarget = getInit(target, type)
else return cloneOtherType(target, type)
// 防止循环引用
if (map.get(target)) return target
map.set(target, cloneTarget)
// 克隆set
if (type === setTag) {
target.forEach((value) => cloneTarget.add(key, clone(value)))
return cloneTarget
}
// 克隆对象和数组
const keys = type === arrayTag ? undefined : Object.keys(target)
forEach(keys || target, (value, key) => {
if (keys) key = value
cloneTarget[key] = clone(target[key], map)
})
return cloneTarget
}
}
function deepCopy (obj, cache = []) {
if (obj === null || typeof obj !== 'object') {
return obj
}
if (Object.prototype.toString.call(obj) === '[object Date]') return new Date(obj)
if (Object.prototype.toString.call(obj) === '[object RegExp]') return new RegExp(obj)
if (Object.prototype.toString.call(obj) === '[object Error]') return new Error(obj)
const item = cache.filter(item = > item.original === obj)[0]
if (item) return item.copy
let copy = Array.isArray(obj) ? [] : {}
cache.push({
original: obj,
copy
})
Object.keys(obj).forEach(key => {
copy[key] = deepCopy(obj[key], cache)
})
return copy
}
deepCopy($obj)