惰性深度克隆实现

2 篇文章 0 订阅
本文介绍了如何使用简单的逻辑和Proxy实现惰性深度克隆,确保在修改值时才进行复制,避免不必要的数据复制。通过创建Map存储目标对象和其真实地址,以及在get和set时进行浅克隆操作,始终保持原有数据不变。同时,提供了仓库地址和兼容IE的解决方案。
摘要由CSDN通过智能技术生成

immutable

介绍

  1. 使用简单的逻辑实现了一个 API,仅修改值时进行复制,最大限度地减少了复制或缓存数据的需求。
  2. 始终产生新的更新数据,不改变原有数据。
  3. 可以使用proxy-polyfill实现ie兼容
  4. 仓库地址https://gitee.com/china_mxb/immutable

软件原理

使用 Proxy 响应更新,仅 get 和 set 时浅克隆操作对象并赋值

  1. 创建一个 Map 集合用来储存 target 和其真实地址
  2. 浅克隆目标对象为 real 对象
  3. 执行回调,实际监听 real 对象。
  4. 触发 get 时,将 val 与其真实地址储存,set 时会用到
  5. 将读取的值浅克隆并赋值,返回新的代理对象
  6. 触发 set 时,获取 target 的真实地址(target 的值不能直接赋值),若有:进行第 5 步,若没有:直接赋值

安装教程

import deepClone from "@personal_simple_code/immutable"

let obj = {
    a: [1, 2, 3, 4, 5],
    b: { c: [123] },
    d: new Map(),
    e: new Set(),
}
let a = deepClone(obj, (x) => {
    x.a = [0, 0, 0]
    x.a[0] = 100
    x.a[1]++
    x.a[0] += x.a[1] + 100

    x.a.push(0)
    x.d.set("a", {
        a: 100,
    })
    x.e.add(1089)
    x.e.add(x.d.get("a"))
    x["f"] = {
        a: x.e,
    }
})

console.error(`原始值:`, obj)
console.error(`结果:`, a)

结果

原始值: { a: [ 1, 2, 3, 4, 5 ], b: { c: [ 123 ] }, d: Map {}, e: Set {} }
结果: {
  a: [ 201, 1, 0, 0 ],
  b: { c: [ 123 ] },
  d: Map { 'a' => { a: 100 } },
  e: Set { 1089, { a: 100 } },
  f: { a: Set { 1089, [Object] } }
}

使用说明

  1. 当前版本对象容器仅支持 Array,Set,Map,Object 类型
  2. 回调函数内的取值,赋值均为直接复制,没有引用关系

简易运行

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    "use strict";
    /**
     *
     * Shallow copy an object. The current version of the object container only supports array, set, map and object types
     *
     * 浅复制一个对象,当前版本对象容器仅支持 Array,Set,Map,Object 类型
     * @param target Target object 目标对象
     */
    var assign = function (target) {
        if (target instanceof Array)
            return target.concat();
        if (target instanceof Map)
            return new Map(target);
        if (target instanceof Set)
            return new Set(target);
        return Object.assign({}, Object(target));
    };
    /**
     * Deep clone an object
     * 深度克隆一个对象
     * @param target
     * @param callback
     */
    function deepClone(target, callback) {
        var map = new Map(); //Store target and its real address 储存 target 和其真实地址
        var real = assign(target); //Shallow clone target object is real object 浅克隆目标对象为 real 对象
        callback.call(real, Clone.create(real, map)); // Actually listening to real objects. 执行回调,实际监听real对象
        return real;
    }
    var Clone = /** @class */ (function () {
        function Clone(obj, map) {
            var clone = new Proxy(obj, {
                get: function (target, prop) {
                    var val = target[prop];
                    map.set(val, {
                        parent: target,
                        key: prop
                    }); //Store Val and its real address, which will be used in set 将 val 与其真实地址储存,set 时会用到
                    switch (typeof val) {
                        case "object":
                            target[prop] = assign(val);
                            //The read value is shallowly cloned and assigned, and the new proxy object is returned  将读取的值浅克隆并赋值,返回新的代理对象
                            return Clone.create(target[prop], map);
                        case "function":
                            return val.bind(target);
                        default:
                            return val;
                    }
                },
                set: function (target, prop, value) {
                    var obj = map.get(
                        target
                    ); //When set is triggered, get the real address of target (the value of target cannot be assigned directly)  触发 set 时,获取 target 的真实地址(target 的值不能直接赋值),
                    if (obj) {
                        var parent_1 = obj.parent,
                            key = obj.key;
                        parent_1[key] = assign(target);
                        parent_1[key][prop] = value;
                    } else {
                        target[prop] = value;
                    }
                    return true;
                }
            });
            this.proxy = clone;
        }
        Clone.create = function (obj, map) {
            return new Clone(obj, map).proxy;
        };
        return Clone;
    }());


    let obj = {
        a: [1, 2, 3, 4, 5],
        b: {
            c: [123]
        },
        d: new Map(),
        e: new Set(),
    }
    let a = deepClone(obj, (x) => {
        x.a = [0, 0, 0]
        x.a[0] = 100
        x.a[1]++
        x.a[0] += x.a[1] + 100

        x.a.push(0)
        x.d.set("a", {
            a: 100,
        })
        x.e.add(1089)
        x.e.add(x.d.get("a"))
        x["f"] = {
            a: x.e,
        }
    })

    console.error(`原始值:`, obj)
    console.error(`结果:`, a)
</script>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值