immutable
介绍
- 使用简单的逻辑实现了一个 API,仅修改值时进行复制,最大限度地减少了复制或缓存数据的需求。
- 始终产生新的更新数据,不改变原有数据。
- 可以使用proxy-polyfill兼容ie
- 仓库地址gitee.com/china_mxb/i…
软件原理
使用 Proxy 响应更新,仅 get 和 set 时浅克隆操作对象并赋值
- 创建一个 Map 集合用来储存 target 和其真实地址
- 浅克隆目标对象为 real 对象
- 执行回调,实际监听 real 对象。
- 触发 get 时,将 val 与其真实地址储存,set 时会用到
- 将读取的值浅克隆并赋值,返回新的代理对象
- 触发 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] } }
}
使用说明
- 当前版本对象容器仅支持 Array,Set,Map,Object 类型
- 回调函数内的取值,赋值均为直接复制,没有引用关系
简易运行
<!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>