手写一个深拷贝函数

145 阅读1分钟

实现思路

对象分为,可遍历对象和不可遍历对象。可遍历对象(set、map、array、object)可通过循环、递归来实现,不可遍历对象通过直接用构造函数和原始数据创建一个新对象来实现。

完整代码


// 可遍历引用类型
const mapType = '[object Map]';
const setType = '[object Set]';
const arrayType = '[object Array]';
const objectType = '[object Object]';

// 不可遍历引用类型
const dateType = '[object Date]';
const errorType = '[object Error]';
const regexpType = '[object RegExp]';
// 实际上深复制函数没有应用场景,并且直接返回即可
const funcType = '[object Function]';

const deepmap = [mapType, setType, arrayType, objectType];
// 是否对象类型
function isObject (target) {
    let type = typeof target;
    return type !== null && (type === 'object' || type === 'function');
}
// 获取数据类型
function getType (target) {
    return Object.prototype.toString.call(target);
}
// 初始化target
function getInit (target) {
    return new target.constructor();
}
// 复制正则表达式
function deepRegexpClone (target) {
    const reFlags = /\w*$/;
    let result = new RegExp(target.source, reFlags.exec(target));
    result.lastIndex = target.lastIndex;
    return result;
}
// 复制日期、错误
function deepDateClone (target) {
    const Ctor = target.constructor;
    return new Ctor(target);
}
function deepClone (target, map = new WeakMap()) {
    if (!isObject(target)) {
        return target;
    }
    let type = getType(target);
    // 可遍历引用类型
    if (deepmap.includes(type)) {
        let result = getInit(target);
        // 处理set类型
        if (type === setType) {
            result.forEach(val => {
                result.set(deepClone(val, map));
            });
        } else if (type === mapType) {
            // 处理map类型
            result.forEach((val, key) => {
                result.set(key, deepClone(val, map));
            });
        } else {
            // 其他类型递归遍历
            for (let key in target) {
                result[key] = deepClone(target[key], map);
            }
        }
        return result;
    } else {
        // 不可遍历引用类型
        let result;
        switch (type) {
            case errorType:
            case dateType:
                result = deepDateClone(target);
                break;
            case regexpType:
                result = deepRegexpClone(target);
                break;
            default:
                result = target;
        }
        return result;
    }
}
let regExpN = /(?<=().+(?=)\s+{)/;
console.log(typeof regExpN, deepClone(regExpN));

上述关于深拷贝函数的实现是自己学习的记录,更详细的实现方法大家可以看一下如何写出一个惊艳面试官的深拷贝? - 掘金 (juejin.cn)