Javascript 使用代理观察地图的更改
我使用MapJavaScript对象。我想观察使用代理对象对地图实例的更改。但是,无论我尝试向代理提供什么处理程序对象,我都会在不兼容的接收器上始终得到调用的错误Javascript 使用代理观察地图的更改,javascript,proxy,ecmascript-6,Javascript,Proxy,Ecmascript 6,我使用MapJavaScript对象。我想观察使用代理对象对地图实例的更改。但是,无论我尝试向代理提供什么处理程序对象,我都会在不兼容的接收器上始终得到调用的错误Method Map.prototype.set。我做错了什么?我希望使用的惯用示例如下所示 var map = new Map(); var proxy = new Proxy(map, { set(obj, prop, value) { console.log(value); } }); proxy.
Method Map.prototype.set
。我做错了什么?我希望使用的惯用示例如下所示
var map = new Map();
var proxy = new Proxy(map, {
set(obj, prop, value) {
console.log(value);
}
});
proxy.set(1, 1); --> error
我还尝试为
apply
设置一个处理程序,但没有任何效果。首先,请理解,您的错误也会在
var map = new Map();
var proxy = new Proxy(map, {});
proxy.set(1, 1);
它与您使用的集合(对象、道具、值)
无关
为什么失败
要进一步打破这一点,请理解这与执行基本相同
var map = new Map();
var proxy = new Proxy(map, {});
Map.prototype.set.call(proxy, 1, 1);
这也是错误。您正在为Map
实例调用set
函数,但将Proxy
而不是Map
实例传递给它
这就是问题的核心所在Map
s使用专门与Map
对象本身关联的专用内部插槽存储数据。代理的行为不是100%透明的。它们允许您截取对象上的一组特定操作,并在操作发生时执行逻辑,这通常意味着将该逻辑代理到其他对象,在您的情况下是从代理
到映射
不幸的是,对于您的情况,代理访问映射实例的私有内部插槽不是可以被拦截的行为之一。你可以想象一下
var PRIVATE = new WeakMap();
var obj = {};
PRIVATE.set(obj, "private stuff");
var proxy = new Proxy(obj, {});
PRIVATE.get(proxy) === undefined // true
PRIVATE.get(obj) === "private stuff" // true
因此,由于对象作为this
传递到Map.prototype.set
不是真实的映射,因此它无法找到所需的数据,并将引发异常
解决方案
这里的解决方案意味着您实际上需要将正确的this
传递到Map.prototype.set
对于代理,最简单的方法是实际拦截对.set
的访问,例如
var map = new Map();
var proxy = new Proxy(map, {
get(target, prop, receiver) {
// Perform the normal non-proxied behavior.
var value = Reflect.get(target, prop, receiver);
// If something is accessing the property `proxy.set`, override it
// to automatically do `proxy.set.bind(map)` so that when the
// function is called `this` will be `map` instead of `proxy`.
if (prop === "set" && typeof value === "function") value = value.bind(target);
return value;
}
});
proxy.set(1, 1);
当然,这并没有解决您关于拦截对.set
的实际调用的问题,因此您可以对此进行扩展
var map = new Map();
var proxy = new Proxy(map, {
get(target, prop, receiver) {
var value = Reflect.get(target, prop, receiver);
if (prop === "set" && typeof value === "function") {
// When `proxy.set` is accessed, return your own
// fake implementation that logs the arguments, then
// calls the original .set() behavior.
const origSet = value;
value = function(key, value) {
console.log(key, value);
return origSet.apply(map, arguments);
};
}
return value;
}
});
proxy.set(1, 1);
您在代码片段中所做的任何事情都不会首先触发
设置陷阱。如果执行newproxy(new Map,{}),代码也会复制。set(1,1)
您既没有为代理分配属性,也没有将其作为函数调用,这就是set
和apply
陷阱都不存在的原因work@Bergi唉,我找了又找不到好的副本,唉,代理将不会持有Map
的方法,比如entries()
?@MaorBane,这些方法应该可以正常工作。