ES6代理模式实现高性能对象深复制

本文介绍了如何利用ES6的代理模式来实现高性能的对象深复制。通过共享读和懒代理策略减少时间和空间消耗。在实现过程中,创建了一个数据结构用于存储原生对象与代理对象的关系,并在赋值时将新值缓存,对象则转化为代理对象,确保始终访问的是代理对象。详细阐述了代理模式的实现思路和具体代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ES6代理模式实现对象深复制

总体介绍:

对于对象深复制,要实现高性能的话,需要减少必要的时间和空间花费,那么代理模式是如何在时间和空间上进行减少开支的呢?

  • 共享读:复制的对象的数据在没有修改之前,读取复制后的对象的值就会把读请求重定向到被复制的对象上面去,只有当数据被修改后,才会从缓存中进行读取。
  • 懒代理:在初始化的时候,不会进行全部代理,而是在访问的时候进行代理,这样就使得cpu的压力分配到不同阶段去,就不会产生很大的开销。

实现思路:

  • 需要存储关系的数据结构:
    • rawToProxyMap:原生对象对应的代理对象的Map,记录所有的原生对象的代理对象,减少代理次数。
    • copyCacheMap:重新赋值后的数据缓存,如果一个代理对象进行重新赋值后,会把数据存储在这里,按照Object->Data进行存储,
  • 对于getter代理:
    • 如果是对象类型的数据,则返回其代理对象,所以用户永远拿到代理对象
    • 如果是基本数据类型,则直接获取基本数据类型。
  • 对于setter
    • 在进行赋值的时候,需要将数据存放到copyCacheMap中,以便下一次访问的时候进行获取,而不是对原始数据进行修改。
    • 新值如果是一个对象的话,那么直接把其设置成代理对象。这是进行懒代理的关键步骤

代码实现

const isArray = array => Array.isArray(array);

const toString = tar => Object.prototype.toString.call(tar);

const sliceType = str => String.prototype.slice.call(str, 8, -1);

const isObject = (tar) => sliceType(toString(tar)) === 'Object';

const proxySymbol = Symbol('CustomProxy');

const isProxy = (tar) => !!tar && !!tar[proxySymbol];

//  Object<- ->proxy
const toProxyMap = new Map();

export const toProxy = (tar) => {
  if (isProxy(tar)) {
    return tar;
  }

  if (isObject(tar) || isArray(tar)) {
    if (toProxyMap.has(tar)) {
      return toProxyMap.get(tar);
    }

    let proxyObject = new Proxy(tar, handler);

    toProxyMap.set(tar, proxyObject);

    return proxyObject;
  }

  return tar;
};

// raw <-  -> copy
const copyCacheMap = new Map();

const handler = {
  get(target, key, receiver) {
    // 内部使用的情况,获取代理对象的原始对象
    if (key === proxySymbol) return target;
    // 在获取数据的时候,如果修改过数据,那么从copy缓存里面进行获取target,并且返回target[key],如果没有修改过数据的话,则直接返回target[key]
    const data = copyCacheMap.get(target) || target;
    return toProxy(data[key]);
  },
  set(target, key, value) {
    let data = getCopy(target);
    // 这里进行深度代理,也就是一层一层懒代理
    let newValue = toProxy(value);

    // 如果新值是一个代理后的对象(也就是不是基本数据类型),那么进行获取原始对象
    data[key] = isProxy(newValue) ? newValue[proxySymbol] : newValue;

    return true;
  }
};

// 将复制好的数据进行缓存
const getCopy = (tar) => {
  if (copyCacheMap.has(tar)) {
    return copyCacheMap.get(tar);
  }

  let data = isArray(tar) ? tar.slice() : {...tar};

  copyCacheMap.set(tar, data);

  return data;
};

let a = {
  a: 'abc',
  b: {
    c: 'abcd'
  },
  d: [1, 2, 3, 4]
};

let proxy = toProxy(a);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值