深浅拷贝


2019/11/21 手写代码 js基础

# 浅拷贝

# 通过解构实现

const shallowCloneByDeconst = obj => ({ ...obj });

# 通过Object.assign实现

const shallowCloneByObjectAssign = obj => Object.assign({}, obj);

# 数组还可通过以下两种方式实现

// 1. Array.prototype.concat()
const shallowCloneByConcat = arr => arr.concat();
// 2. Array.prototype.slice()
const shallowCloneBySlice = arr => arr.slice();

# 深拷贝

# 通过json实现

  • 缺陷
    1. 不能处理函数,会被转换成null
    2. 只能处理普通对象
const deepCloneByJson = obj => JSON.parse(JSON.stringify(obj));

# 通过递归实现

  • 思路
    • 递归查看对象中的可枚举属性,若是基本类型则赋值,若是引用类型则递归
    • 使用 WeakMap 处理环
    • 使用结构化方式分别处理不同类型的对象
  • 缺陷 - 不能处理固有对象及宿主对象
// 获取构造函数类型
const getCtorType = tar => Object.prototype.toString.call(tar).slice(8, -1);
// 判断是否是引用类型
const isObject = target => target && (typeof target == 'object' || typeof target == 'function');
// 拷贝函数
const 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]);
            } else {
                return new Function(body[0]);
            }
        } else {
            return null;
        }
    } else {
        return eval(funcString);
    }
}

/**
 * 递归深拷贝
 * @param {any} obj 待拷贝对象
 * @param {WeakMap | undefined} dict 处理循环引用所使用的字典
 */
const deepClone = (obj, dict = new WeakMap()) => {
    // 处理基本类型
    if (!isObject(obj)) return obj;
    // 处理环
    if (dict.has(obj)) return dict.get(obj);

    let newObj;
    let type = getCtorType(obj);

    switch (type) {
        case 'Number':
            newObj = new Number(obj.valueOf());
            break;

        case 'String':
            newObj = new String(obj.toString());
            break;

        case 'Boolean':
            newObj = new Boolean(obj.valueOf());
            break;

        case 'Date':
            newObj = new Date(obj.getTime());
            break;

        case 'Function':
            newObj = cloneFunction(obj);
            break;

        case 'Symbol':
            newObj = Object(Symbol.prototype.valueOf.call(newObj));
            break;

        case 'RegExp':
            newObj = new RegExp(obj.source /* 匹配表达式 */, /\w*$/.exec(obj) /* 匹配模式 */);
            // 重置上次匹配后的位置记录
            newObj.lastIndex = obj.lastIndex;
            break;

        case 'Error':
            newObj = new Error(obj.toString().slice(7, -1));
            break;

        default:
            newObj = new obj.constructor(obj);
            break;
    }
    for (const key in obj) {
        newObj[key] = isObject(obj[key])
            ? deepClone(obj[key])
            : obj[key];
    }
    dict.set(obj, newObj);

    return newObj;
};
Last Updated: 12/21/2019, 11:39:15 AM