利用解构实现得深拷贝-处理对象/数组内多层嵌套对象--非考虑所有情况

163 阅读1分钟

区别其他深拷贝实现--用上解构能够保持数据一致性-而不像JSON.parse(JSON.stringify())实现会导致一些数据发生变化:比如时间对象new Date()会变成字符串,error对象/函数会变成{}等

浅拷贝用展开符就行let newObj={...cloneObj}

let a = {
    name: [
        {
            secName: undefined,
            errName: new Error(),
            thirdName: () => { },
            secArr: [
                {
                    test: {
                        swim: 123
                    }
                },
                [                    { name: 12345 }                ]
            ]
        }
    ],
    doubleObj: {
        thirdObj: 2134
    }
}
/**核心代码-start**/
const deepClone=(newcurr)=>{
  newcurr={...newcurr}
  for (const key in newcurr) {
      if(newcurr[key] instanceof Object){
          newcurr[key]=deepClone(newcurr[key])
      }
  }
  return newcurr
}

/**核心代码-end**/


考虑完整情况比如循环引用/递归爆栈可以参考现有方案 主要是采用栈+while替代递归/map结构来看是否集中缓存来返回引用


const { toString, hasOwnProperty } = Object.prototype;

function hasOwnProp(obj, property) {
    return hasOwnProperty.call(obj, property)
}

function getType(obj) {
    return toString.call(obj).slice(8, -1).toLowerCase();
}

function isObject(obj) {
    return getType(obj) === "object";
}

function isArray(arr) {
    return getType(arr) === "array";
}

function isCloneObject(obj) {
    return isObject(obj) || isArray(obj)
}

function cloneDeep(x) {
    let uniqueData = new WeakMap();
    let root = x;

    if (isArray(x)) {
        root = [];
    } else if (isObject(x)) {
        root = {};
    }

    // 循环数组
    const loopList = [        {            parent: root,            key: undefined,            data: x,        }    ];

    while (loopList.length) {
        // 深度优先
        const node = loopList.pop();
        const parent = node.parent;
        const key = node.key;
        const source = node.data;

        // 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
        let target = parent;
        if (typeof key !== 'undefined') {
            target = parent[key] = isArray(source) ? [] : {};
        }

        // 复杂数据需要缓存操作
        if (isCloneObject(source)) {
            // 命中缓存,直接返回缓存数据
            let uniqueTarget = uniqueData.get(source);
            if (uniqueTarget) {
                parent[key] = uniqueTarget;
                continue; // 中断本次循环
            }

            // 未命中缓存,保存到缓存
            uniqueData.set(source, target);
        }

        if (isArray(source)) {
            for (let i = 0; i < source.length; i++) {
                if (isCloneObject(source[i])) {
                    // 下一次循环
                    loopList.push({
                        parent: target,
                        key: i,
                        data: source[i],
                    });
                } else {
                    target[i] = source[i];
                }
            }
        } else if (isObject(source)) {
            for (let k in source) {
                if (hasOwnProp(source, k)) {
                    if (isCloneObject(source[k])) {
                        // 下一次循环
                        loopList.push({
                            parent: target,
                            key: k,
                            data: source[k],
                        });
                    } else {
                        target[k] = source[k];
                    }
                }
            }
        }
    }

    uniqueData = null;
    return root;
}