js自己写深克隆

225 阅读1分钟

请结合# ConardLi#### segmentfault.com/a/119000002… 来看!!!

const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';
// 无法继续遍历的对象
const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const numberTag = '[object Number]';
const regexpTag = '[object RegExp]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const funcTag = '[object Function]'

var deepTag = [mapTag, setTag, arrayTag, objectTag]
var baseTag= [boolTag, dateTag, errorTag, numberTag, regexpTag, stringTag, symbolTag]
// 初始化对象
function getInit (target) {
    const Ctor = target.constructor;
    return new Ctor();
}

// 获取类型
function getType (target) {
    return Object.prototype.toString.call(target);
}

// 克隆Symbol
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();
    console.info(funcString)
    if (func.prototype) {
        console.log('普通函数');
        const param = paramReg.exec(funcString);
        const body = bodyReg.exec(funcString);
        if (body) {
            console.log('匹配到函数体:', body[0]);
            if (param) {
                const paramArr = param[0].split(',');
                console.log('匹配到参数:', paramArr);
                return new Function(...paramArr, body[0]);
            } else {
                return new Function(body[0]);
            }
        } else {
            return null;
        }
    } else {
        return eval(funcString);
    }
}
// 克隆不可再分Object类型
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 regexpTag:
            return cloneReg(target);
        case symbolTag:
            return cloneSymbol(target);
        default:
            return null;
    }
}

function forEach(array, iteratee) {
    let index = -1;
    const length = array.length;
    while (++index < length) {
        iteratee(array[index], index);
    }
    return array;
}
// 判断是否为object或者是function
function isObject(target) {
    const type = typeof target;
    return target !== null && (type === 'object' || type === 'function' || type === 'symbol');
}


function clone (target, map = new WeakMap()) {
    // 克隆原始类型
    if (!isObject(target)) {
        return target;
    }
    let cloneTarget;
    const type = getType(target);
    if (deepTag.includes(type)) {
        cloneTarget = getInit(target)
    }
    // 防止循环引用
    if(map.get(target)) {
        return map.get(target);
    }
    map.set(target, cloneTarget);
    // 克隆不可继续递归的属性
    if (baseTag.includes(type)) {
        cloneTarget = cloneOtherType(target, type);
        return cloneTarget;
    }
    // 克隆set
    if (type === setTag) {
        target.forEach(value =>{
            cloneTarget.add(clone(value, map))
        })
        return cloneTarget;
    }
    // 克隆map
    if (type === mapTag) {
        target.forEach((value, key)=>{
            cloneTarget.set(key, clone(value, map));
        });
        return cloneTarget;
    }

    // 克隆函数
    if(type == funcTag) {
        return cloneFunction(target);
    }
    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;
}


let person = {name: 'dingdang', age: 3};
console.info(person)
let dingdang = this.clone(person)
console.info(dingdang)