【JavaScript进阶】手写深度克隆函数(循环递归方式)

以下是使用递归+循环方式手写功能全面的深度克隆函数,包含原型链指向,排除原型上的属性以及考虑环形引用的情况,采取缓存措施处理有可能导致的内存泄漏的情况。

// 手写深度克隆函数

// 缓存一下被克隆过的对象,防止环形引用造成无限递归
// 使用WeakMap,比Map更好,防止对象使用后由于Map中有引用而不会被回收,造成内存泄漏
const cache = new WeakMap();

function deepClone(value) {
    // 如果是原始类型,直接返回
    if (typeof value !== 'object' || value === null) {
        return value;
    }
    // 先从缓存取一下原对象是否已经被克隆过,有值直接返回
    const cached = cache.get(value);
    if (cached) {
        return cached;
    }
    // 引用类型,创建空数组/对象接受克隆后的值
    const result = Array.isArray(value) ? [] : {};
    // 将原对象和克隆的对象设置到缓存中
    cache.set(value, result);
    // 设置一下原型链,让克隆出来的对象的原型与原对象原型保持一致
    Object.setPrototypeOf(result, Object.getPrototypeOf(value))
    // 循环原对象每个key,赋值到新对象中
    for (const key in value) {
        // 排除prototype原型上的属性,不克隆原型上的属性
        if (value.hasOwnProperty(key)) {
            // 针对原对象中每个值递归再深度克隆一次
            result[key] = deepClone(value[key])
        }
    }
    return result
}

// 测试一下

function Test(x, y) {
    this.x = x;
    this.y = y;
}

Test.prototype.z = 'z'

var p = new Test(1, 2);
p.a =  [1,2,3]
p.c = p // 环形引用

const newP = deepClone(p)

console.log('origin p: ', p) // Test { x: 1, y: 2, a: [ 1, 2, 3 ], c: [Circular] }
console.log('new p: ', newP) // Test { x: 1, y: 2, a: [ 1, 2, 3 ], c: [Circular] }
console.log(p.prototype === newP.prototype) // true
console.log(p.a === newP.a) // false

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值