const getType = obj => Object.prototype.toString.call(obj);
const isObject = (target) => (typeof target === ‘object’ || typeof target === ‘function’) && target !== null;
const canTraverse = {
‘[object Map]’: true,
‘[object Set]’: true,
‘[object Array]’: true,
‘[object Object]’: true,
‘[object Arguments]’: true,
};
const mapTag = ‘[object Map]’;
const setTag = ‘[object Set]’;
const boolTag = ‘[object Boolean]’;
const numberTag = ‘[object Number]’;
const stringTag = ‘[object String]’;
const symbolTag = ‘[object Symbol]’;
const dateTag = ‘[object Date]’;
const errorTag = ‘[object Error]’;
const regexpTag = ‘[object RegExp]’;
const funcTag = ‘[object Function]’;
const handleRegExp = (target) => {
const {source, flags} = target;
return new target.constructor(source, flags);
}
const handleFunc = (func) => {
// 箭头函数间接返回本身
if(!func.prototype) return func;
const bodyReg = /(?<={)(.|n)+(?=})/m;
const paramReg = /(?<=().+(?=)s+{)/;
const funcString = func.toString();
// 别离匹配 函数参数 和 函数体
const param = paramReg.exec(funcString);
const body = bodyReg.exec(funcString);
if(!body) return null;
if (param) {
const paramArr = param[0].split(',');
return new Function(...paramArr, body[0]);
} else {
return new Function(body[0]);
}
}
const handleNotTraverse = (target, tag) => {
const Ctor = target.constructor;
switch(tag) {
case boolTag:
return new Object(Boolean.prototype.valueOf.call(target));
case numberTag:
return new Object(Number.prototype.valueOf.call(target));
case stringTag:
return new Object(String.prototype.valueOf.call(target));
case symbolTag:
return new Object(Symbol.prototype.valueOf.call(target));
case errorTag:
case dateTag:
return new Ctor(target);
case regexpTag:
return handleRegExp(target);
case funcTag:
return handleFunc(target);
default:
return new Ctor(target);
}
}
const deepClone = (target, map = new WeakMap()) => {
if(!isObject(target))
return target;
let type = getType(target);
let cloneTarget;
if(!canTraverse[type]) {
// 解决不能遍历的对象
return handleNotTraverse(target, type);
}else {
// 这波操作相当要害,能够保障对象的原型不失落!let ctor = target.constructor;
cloneTarget = new ctor();
}
if(map.get(target))
return target;
map.set(target, true);
if(type === mapTag) {
// 解决 Map
target.forEach((item, key) => {cloneTarget.set(deepClone(key, map), deepClone(item, map));
})
}
if(type === setTag) {
// 解决 Set
target.forEach(item => {cloneTarget.add(deepClone(item, map));
})
}
// 解决数组和对象
for (let prop in target) {
if (target.hasOwnProperty(prop)) {cloneTarget[prop] = deepClone(target[prop], map);
}
}
return cloneTarget;
}