计算机语言

手写源码-实现深拷贝

2021-08-31  本文已影响0人  胡小喵_

实现一个深拷贝,包括 Symbol 类型及 Regexp(正则)的拷贝

  1. 初级版
// 数据类型 
let target = {
   field1: 1,
   field2: undefined,
   field3: 'field3',
   field4: {
     child1: {
       _child1: 1
     },
     child2: '2'
   }
 };

// 代码实现
function deepClone(target) {
    if (Object.prototype.toString.call(target) == '[object Object]') {
        let cloneTarget = {};
        Object.keys(target).forEach(key => {
            const item = target[key];
            cloneTarget[key] = deepClone(item);
        });
        return cloneTarget;
    }
    return target;
}
  1. 终极版:可处理循环引用
// 数据类型 
let target = {
   field1: 1,
   field2: undefined,
   field3: 'field3',
   field4: {
     child1: {
       _child1: 1
     },
     child2: '2'
   }
 };
target.target = target;

function deepClone(target, map = new WeakMap()) {
    if (
        Object.prototype.toString.call(target) == '[object Object]' ||
        Object.prototype.toString.call(target) == '[object Array]'
    ) {
        let cloneTarget = Object.prototype.toString.call(target) == '[object Object]' ? {} : [];
        if (map.get(target)) {
            return target;
        }
        map.set(target, cloneTarget);
        Object.keys(target).forEach(key => {
            const item = target[key];
            cloneTarget[key] = deepClone(item, map);
        });
        return cloneTarget;
    }
    return target;
}
  1. 把 forEach 转换为 性能更好的 while
function _forEach(array, fn) {
    let index = -1,
        len = array.length;
    while (++index < len) {
        fn(array[index], index, array);
    }
}

function deepClone(target, map = new WeakMap()) {
    if (
        Object.prototype.toString.call(target) == '[object Object]' ||
        Object.prototype.toString.call(target) == '[object Array]'
    ) {
        let cloneTarget = Object.prototype.toString.call(target) == '[object Object]' ? {} : [];
        if (map.get(target)) {
            return target;
        }
        map.set(target, cloneTarget);
        _forEach(Object.keys(target), key => {
            const item = target[key];
            cloneTarget[key] = deepClone(item, map);
        });
        return cloneTarget;
    }
    return target;
}

究极版

let target = {
    field1: 1,
    field2: undefined,
    field3: 'field3',
    field4: {
        child1: {
            _child1: 1
        },
        child2: '2'
    },
    field4: [1, 2, 3],
    reg: /\w*$/g
};
target.target = target;

let TAG_MAP_FUN = {};
function setTagsMap() {
    ['Set', 'Map', 'Object', 'Array', 'Function', 'RegExp', 'Symbol'].forEach(key => {
        TAG_MAP_FUN['is' + key] = function () {
            return Object.prototype.toString.call(arguments[0]) == `[object ${key}]`;
        };
    });
}
setTagsMap();

// 引用类型 和 null 的 typeof 都为 object
function isReference(target) {
    const type = typeof target;
    return target !== null && (type === 'object' || type === 'function');
}

function getInit(target) {
    const Cons = target.constructor;
    return new Cons();
}

function deepClone(target, map = new WeakMap()) {
    if (TAG_MAP_FUN.isRegExp(target)) {
        let newTarget = target.constructor(target.source, /\w*$/.exec(target));
        newTarget.lastIndex = target.lastIndex;
        return newTarget;
    }
    if (!isReference(target) || TAG_MAP_FUN.isFunction(target)) {
        return target;
    }

    // 引用类型
    let cloneTarget = getInit(target);

    // 放置引用类型循环引用
    if (map.get(target)) {
        return target;
    }
    map.set(target, cloneTarget);

    if (TAG_MAP_FUN.isSet(target)) {
        target.forEach(value => {
            cloneTarget.add(deepClone(value, map));
        });
    }
    if (TAG_MAP_FUN.isMap(target)) {
        target.forEach((value, key) => {
            cloneTarget.set(key, deepClone(value, map));
        });
    }
    if (TAG_MAP_FUN.isObject(target) || TAG_MAP_FUN.isArray(target)) {
        Object.keys(target).forEach(key => {
            const value = target[key];
            cloneTarget[key] = deepClone(value, map);
        });
    }

    return cloneTarget;
}

let newTarget = deepClone(target);

上一篇 下一篇

猜你喜欢

热点阅读