前端面试--js基础(实现深拷贝和浅拷贝)

// 首先明确深、浅拷贝的概念和区别:浅拷贝是对原始对象的属性值进行拷贝,如果原始对象是基本数据类型,直接拷贝值,
// 如果是引用数据类型,就拷贝原始对象的引用,也就是内存地址,这时候如果其中一个对象引用的内存地址发生变化。另一个对象也会发生相同变化
// 而深拷贝如果属性值是引用数据类型,会新建一个引用类型并把对应值复制过去,两个对象的内存地址是互相独立的,对其中一个的改变不会对另一个产生影响
// 1、一般浅拷贝通过Object.assign()、...扩展运算符、数组的Array.prototype.slice Array.prototype.concat来实现
// 2、一般深拷贝通过JSON.parse(JSON.stringfy(obj))、lodash库的—_cloneDeep方法实现 
// 手写浅拷贝
function shallowCopy(object) {
    // 判断是否是对象
    if (!object || typeof object !== 'object') return object;
    // 看对象是数组还是简单的对象写法
    let newObj = Array.isArray(object) ? [] : {};
    for (let key in object) {
        // 使用此API忽略继承属性
        if (object.hasOwnProperty(key)) {
            newObj[key] = object[key];
        }
    }
    return newObj
}
// 手写深拷贝(简单写法 -- 缺陷是循环引用 递归死循环导致栈溢出)
function deepCopy(object) {
    if (!object || typeof object !== 'object') return object;
    let newObj = Array.isArray(object) ? [] : {};
    for (let key in object) {
        // 使用此API忽略继承属性
        if (object.hasOwnProperty(key)) {
            // 因为对象可能嵌套很多层引用类型的对象,所以递归实现
            newObj[key] = typeof object[key] === 'object' ? deepCopy(object[key]) : object[key]
        }
    }
    return newObj
}
const target = {
    field1:1,
    field2:undefined,
    field3:{
        child:'child'
    },
    field4:[1,2,3],
}
target.target = target;
// deepCopy(target)
// 解决方案:额外开辟一个存储空间,存储的是原始对象和拷贝对象之间的对应关系,深拷贝时先去这个存储空间找,如果已经拷贝过这个对象直接返回,没有就继续拷贝
// 手写深拷贝(解决循环引用)
function deepCopy2(object,map=new Map()) {
    if (!object || typeof object !== 'object') return object;
    if(object instanceof Date) return new Date(object);
    if(object instanceof RegExp) return new RegExp(object);
    let newObj = Array.isArray(object) ? [] : {};
    if (map.get(object)) {
        return map.get(object);
    }
    map.set(object,newObj)
    for (let key in object) {
        // 使用此API忽略继承属性
        if (object.hasOwnProperty(key)) {
            // 因为对象可能嵌套很多层引用类型的对象,所以递归实现
            newObj[key] = typeof object[key] === 'object' ? deepCopy2(object[key],map) : object[key]
        }
    }
    return newObj;
}
// console.log(deepCopy2(target,map=new Map()));
// 手写深拷贝(考虑循环引用、weakMap优化、for in改while优化性能、考虑其他数据类型--包括可遍历和不可遍历的)
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';
const argsTag = '[object Arguments]';

const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';

const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];


function forEach(array, iteratee) {
    let index = -1;
    const length = array.length;
    while (++index < length) {
        iteratee(array[index], index);
    }
    return array;
}

function isObject(target) {
    const type = typeof target;
    return target !== null && (type === 'object' || type === 'function');
}

function getType(target) {
    return Object.prototype.toString.call(target);
}

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

function cloneSymbol(targe) {
    return Object(Symbol.prototype.valueOf.call(targe));
}

function cloneReg(targe) {
    const reFlags = /\w*$/;
    const result = new targe.constructor(targe.source, reFlags.exec(targe));
    result.lastIndex = targe.lastIndex;
    return result;
}

function 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);
    }
}

function cloneOtherType(targe, type) {
    const Ctor = targe.constructor;
    switch (type) {
        case boolTag:
        case numberTag:
        case stringTag:
        case errorTag:
        case dateTag:
            return new Ctor(targe);
        case regexpTag:
            return cloneReg(targe);
        case symbolTag:
            return cloneSymbol(targe);
        case funcTag:
            return cloneFunction(targe);
        default:
            return null;
    }
}

function clone(target, map = new WeakMap()) {

    // 克隆原始类型
    if (!isObject(target)) {
        return target;
    }

    // 初始化
    const type = getType(target);
    let cloneTarget;
    if (deepTag.includes(type)) {
        cloneTarget = getInit(target, type);
    } else {
        return cloneOtherType(target, type);
    }

    // 防止循环引用
    if (map.get(target)) {
        return target;
    }
    map.set(target, cloneTarget);

    // 克隆set
    if (type === setTag) {
        target.forEach(value => {
            cloneTarget.add(clone(value));
        });
        return cloneTarget;
    }

    // 克隆map
    if (type === mapTag) {
        target.forEach((value, key) => {
            cloneTarget.set(key, clone(value));
        });
        return cloneTarget;
    }

    // 克隆对象和数组
    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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值