深度拷贝 deepClone

/**
 * 深度克隆对象
 * @param {*} value 需要克隆的值 
 * @param {WeakMap} cache 使用 WeakMap 解决环形引用问题,防止内存泄漏 
 */
function deepClone(value, cache = new WeakMap()) {
    // 基础数据
    if(typeof value !== 'object' || value === null) {
        return value;
    }
    // 解决环形引用问题
    if(cache.has(value)) {
        return cache.get(value);
    }
    const toString = Object.prototype.toString.call(value).slice(8,-1);
    if(toString === 'Date') { // 日期时间
        const result = new Date();
        Object.setPrototypeOf(result, Object.getPrototypeOf(value));
        return result;
    } else if(toString === 'Map' || toString === 'Set') { // 集合类型
        const result = toString === 'Map'? new Map() : new Set();
        Object.setPrototypeOf(result, Object.getPrototypeOf(value));
        value.forEach(function(item, key) {
            let nkey, nval;
            if(typeof key === 'object' && key !== null) {
                nkey = deepClone(key, cache)
                cache.set(key, nkey)
            } else {
                nkey = key
            }
            if(typeof item === 'object' && item !== null) {
                nval = deepClone(item, cache)
                cache.set(item, nval)
            } else {
                nval = item
            }
            toString === 'Map' ? this.set(nkey, nval) : this.add(nval)
        }, result)
        return result;
    } else {
        // 克隆结果 1.数组 2.对象
        const result = Array.isArray(value) ? [] : {};
        // 设置克隆结果的原型链为 value 的原型链(即保持原型一致)
        Object.setPrototypeOf(result, Object.getPrototypeOf(value));
        // 环形引用时将克隆的值储存到缓存中
        cache.set(value, result)
        for(const key in value) {
            // 排除原型上的属性
            if (Object.prototype.hasOwnProperty.call(value, key)) {
                if(typeof value[key] === 'object' && value[key] !== null) {
                    result[key] = deepClone(value[key], cache)
                } else {
                    result[key] =  value[key]
                }
            }
        }
        return result;
    }
}

测试例子

var date = new Date()
var dated2 = deepClone(date)
date.setFullYear(2015)
dated2.setFullYear(2018)
console.log(date);
console.log(dated2);

var map1 = new Map();
map1.set('name', '小明')
var foo = {age:18}
map1.set(foo, {nation:'汉族'})
map1.set('bar', {a:'abc'})
var map2 = deepClone(map1)

map1.set('name','张三')
var bar = map1.get('bar')
bar.a = 'def'
foo.age = 22
map1.set('bar', bar)

var foo2 = map1.get(foo)
foo2.nation = "中国"

map2.set('name','李四')
console.log(map1);
console.log(map2);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值