策略模式实现深度拷贝

深度拷贝

区别于浅拷贝:
浅拷贝:对不同数据类型表现不同,对于基本数据类型(布尔、数值、string、null、undefined、Symbol),拷贝基本数据类型的值;对于引用数据类型(Object、Array、Date、Error、Number、String、Boolean等),拷贝的是内存地址(其中一个变化会影响到另外一个元素)
深拷贝:主要是对于引用数据类型,新拷贝元素(每一层)都拥有一个新的内存空间,不会和原来的元素公用一块内存空间

策略模式

策略模式是为了避免过多的if else if else嵌套,方便代码扩展

参考链接: 深入浅出js中的策略模式

分析

分析,如何完成深度拷贝
(1) 区分基本数据和引用数据
(2) 从引用数据里分出 可遍历和不可遍历数据分开处理
(3)注意循环引用的问题

判断数据类型
// 区分是否为对象
const isObject = (o) => {
	return (o !== null) && (typeof o === 'object' || typeof o === 'function');
}
// 准确判断引用数据类型
const typeTag = (o) => {
	return Object.prototype.toString.call(o).slice(8, -1);
}

注: typeof 检测Symbol类型,返回symbol

const isObject = (o) => {
    return o !== null && (typeof o === 'obejct' || typeof o === 'function');
}

const typeTag = (o) => {
    return Object.prototype.toString
        .call(o)
        .slice(8,-1);
}
const cloneTarget = null;

const cloneArrayorObject = (target) => {
    for (const key in target) {
        cloneTarget[key] = clone(target[key], map);
    }
    return cloneTarget;
}
const cloneFunction = (target) => {
    // 参数 ,函数体
    const bodyReg = /(?<={)(.|\n)+(?=})/m;
    const paramReg = /(?<=\().+(?=\)\s+{)/;
    const funcString = target.toString();
    if (target.prototype) {
        const params = paramReg.exec(funcString);
        const body = bodyReg.exec(funcString);
        if (body) {
            if (params) {
                const paramArr = params[0].split(',');
                return new Function(...paramArr, body[0]);
            } else {
                return new Function(body[0]);
            }
        } else {
            return null;
        }
    } else {
        return evel(funcString);
    }
}
const cloneReg = (target) => {
    let flags = /\w*$/;
    let result = new RegExp(target.source, flags.exec(target));
    result.lastIndex = target.lastIndex;
    return result;
}
const cloneBase = (target) => {
    return target.constructor(target);
}
const strategy = {
    'Object': cloneArrayorObject,
    'Array': cloneArrayorObject,
    'Base': cloneBase,
    'Date': function(o) {
        return new Date(+o);
    },
    'RegExp': function(o) {
        const flags = /\w*$/;
        const result = new RegExp(o.source, flags.exec(o));
        reult.lastIndex = o.lastIndex;
        return result;
    },
    'Set': function(o) {
        o.forEach((value,key) => {
            cloneTarget.add(clone(value));
        })
        return cloneTarget;
    },
    'Map': function(o) {
        o.forEach((value, key) => {
            cloneTarget.set(key, clone(value));
        })
        return cloneTarget;
    },
    'Symbol': function(o) {
        return Object(Symbol.prototype.valueOf.call(o));
    },
    'Function': cloneFunction,
}
const hasArg = ['Boolean', 'Nubmer', 'String', 'Error', 'Date'];
// 如果是数组
// weakmap 对象设置为键,没有Iterator,因为垃圾回收不知道什么时候进行,所以就不能进行遍历
// 缓存的时候用到

function clone (target, map = new WeakMap()){
    if (!isObject(target)) {
        return target;
    }
    let type = typeTag(target);
    if (!hasArg.includes(type)) {
        // 初始化cloneTarget
        cloneTarget = new type();
    } else {
        type = 'base';
    }
    // 防止循环引用
    if (map.get(target)) {
        return target;
    }
    map.set(target,cloneTarget);
    return strategy[type](target);
}

注:JSON.stringifyJSON.parse可以实现深度拷贝,但是注意1. 字符串化的时候,忽略undefined、function、正则、Symbol; 2. 不能循环引用 ,报错3. 对于数组、对象、Map、Set只能序列化可遍历属性 4.Date序列化的时候,转换成字符串

参考地址:

[1] 如何写出一个惊艳面试官的深拷贝
[2] JavaScript如何实现深拷贝
[3] JSON.stringify()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值