function deepProxy(target, path = []) {
const changedValues = {};
const handler = (path) => ({
set: function (obj, prop, value) {
console.log(`属性 ${prop} 被设置为 ${value}`);
obj[prop] = value;
setChangedValue(changedValues, [...path, prop], value);
return true;
},
get: function (obj, prop) {
if (typeof obj[prop] === "object" && obj[prop] !== null) {
// 处理数组
if (Array.isArray(obj[prop])) {
return new Proxy(obj[prop], arrayHandler([...path, prop]));
}
// 处理对象
return new Proxy(obj[prop], handler([...path, prop]));
}
return obj[prop];
},
});
const arrayHandler = (path) => ({
set: function (obj, prop, value) {
console.log(`属性 ${prop} 被设置为 ${value}`);
obj[prop] = value;
if (!isNaN(prop)) {
setChangedValue(changedValues, [...path, prop], obj.slice());
}
return true;
},
get: function (obj, prop) {
if (typeof obj[prop] === "object" && obj[prop] !== null) {
// 处理数组
if (Array.isArray(obj[prop])) {
return new Proxy(obj[prop], arrayHandler([...path, prop]));
}
// 处理对象
return new Proxy(obj[prop], handler([...path, prop]));
}
return obj[prop];
},
});
const proxy = new Proxy(target, handler(path));
return {
proxy,
changedValues,
};
}
function setChangedValue(obj, path, value) {
const lastIndex = path.length - 1;
for (let i = 0; i < lastIndex; i++) {
const prop = path[i];
if (!(prop in obj)) {
obj[prop] = typeof path[i + 1] === "number" ? [] : {};
}
obj = obj[prop];
}
obj[path[lastIndex]] = value;
}
const obj = {
a: 1,
b: {
c: 2,
d: {
e: 3,
},
},
f: [4, 5, {g: 6}],
};
const {proxy, changedValues} = deepProxy(obj);
proxy.a = 7;
proxy.b.c = 8;
proxy.b.d.e = 9;
proxy.f[0] = 10;
proxy.f[2].g = 11;
console.log(changedValues)
生成结果
{
"a": 7,
"b": {
"c": 8,
"d": {
"e": 9
}
},
"f": {
"0": [
10,
5,
{
"g": 11
}
],
"2": {
"g": 11
}
}
}
多生成了一个{g:11}
期望结果
const obj1 = {
a: 7,
b: {
c: 8,
d: {
e: 3,
},
}, f: [10, 5, {g: 11}],
}
您好,楼主,您在最开始的时候设置了一个setChangedValue 函数,根据前面代码的含义,你应该是想对这个变化值进行记录
但是在后面的代码中,在处理对象类型属性时,没有看到进行类似操作。因为你没有进行深拷贝处理,导致最终生成结果中多出了一个{g:11}。这里我用一张图描述下深拷贝浅拷贝区别
因此要解决这个问题,你可以试试JSON.parse(JSON.stringify()) 方法进行转换,并将转换后
的值存储到变化记录对象中。这样可以保证记录对象和原始数据之间不存在引用关系,避免互相影响。因此应该在你的代码基础上简单修改下(示例代码已本地测试正常):
修改后就可以正常运行且不会多一个值了。