用Proxy监控对象属性更改,arr数组直接压入被修改的操作,比如键名称和原始值。简单示例如下
<script>
var ops = [];
var obj = {old:111};
var proxy = new Proxy(obj, {
set: function (target, key, value, receiver) {
let op = { key};
if (target[key] === undefined) {//不存在这个属性则标记操作未新增
op.op = 'add';
} else {
op.op = 'update';
op.value = target[key];//存储旧值
}
ops.push(op);
return Reflect.set(target, key, value, receiver)
},
deleteProperty: function (target, key) {
let op = { key, value:target[key], op: 'delete' };
ops.push(op);
delete target[key];
return true;
}
});
delete proxy.old;
console.log(JSON.stringify(obj))
console.log(JSON.stringify(ops))
console.log('\n\n')
proxy.prop1 = 'prop1value'
console.log(JSON.stringify(obj))
console.log(JSON.stringify(ops))
console.log('\n\n')
proxy.prop1 = 'prop1-new-value'
console.log(JSON.stringify(obj))
console.log(JSON.stringify(ops))
console.log('\n\n')
let op
while (op = ops.pop()) {
if (op.op == 'update') {//修改则还原原旧值
obj[op.key] = op.value;//还原原来的值
}
else if (op.op == "add") {//新增,反向操作则是删除
console.log(op.key)
delete obj[op.key];
}
else if (op.op == 'delete') {//删除操作补回属性
obj[op.key] = op.value;
}
console.log(JSON.stringify(obj))
console.log(JSON.stringify(ops))
console.log('\n\n')
}
</script>
下面是 Proxy 支持的拦截操作一览,一共 13 种。
get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。
set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
具体可以参考阮一峰老师的教程
ES6 入门教程
https://es6.ruanyifeng.com/?search=Proxy&x=11&y=2#docs/proxy