Javascript ES6代理中的意外设置陷阱行为

Javascript ES6代理中的意外设置陷阱行为,javascript,node.js,es6-proxy,es6-map,Javascript,Node.js,Es6 Proxy,Es6 Map,我试图截取地图对象上的set和get操作。我决不会试图扩展地图/将其子类化。 在代理上述Map对象的过程中,我遇到了一个奇怪的意外行为,上面的代码中没有触发set陷阱,而是触发了get陷阱两次 我进一步按照以下方式记录get陷阱中的k(key)值: let ar = []; let p = new Proxy(new Map(), { get: (o, k) => { ar.push(1) return Reflect.get(o, k).bind(o) }, set: (

我试图截取地图对象上的set和get操作。我决不会试图扩展地图/将其子类化。 在代理上述Map对象的过程中,我遇到了一个奇怪的意外行为,上面的代码中没有触发set陷阱,而是触发了get陷阱两次

我进一步按照以下方式记录get陷阱中的k(key)值:

let ar = []; 
let p = new Proxy(new Map(), { 

get: (o, k) => {
 ar.push(1)
  return Reflect.get(o, k).bind(o) 
},

set: (o, k, v) => {
 ar.push(2)
  return Reflect.set(o, k, v)
}
});
p.set(1, 2)
p.get(1)
console.log(ar) //Outputs [1,1]
我所期望的行为是数组在get陷阱处为
[2,1]
console.log(k)
,以实际输出键的值

我想知道为什么会发生这种情况,我在这里遇到了一些与代理映射相关的问题,没有一个能够合理地解释为什么会发生这种情况

我的最终目标是在设定的陷阱中触发一个事件。我是在用代理来做它应该用的东西吗?如果没有,我应该采取什么方法?我是否应该放弃使用对象文字的映射,即使它会带来使用映射的所有缺点?例如:无长度属性、仅字符串属性、无强制唯一键等

更新:我越深入这个代理地图,我遇到的问题就越多。在我看来,ES6代理API对待映射的方式与对待普通对象的方式相同。维尔的回答和我的挖掘证实了这一点。我为什么这么说?阅读以下内容

//same code above
get: (o, k) => {
 console.log(k) //Logs set and then get!
  return Reflect.get(o, k).bind(o) 
}
//same code below
上面的代码理论上不应该成功,对吗?这就好像代理在拦截地图时也在使用相同的逻辑来拦截对象操作一样!As

//same code above
 get: (o, k) => {
     if(k === 'tray') return ']'
      return Reflect.get(o, k).bind(o) 
    }
    //same code below
p.tray //returns ] 
Vill的回答是代理将
Map.prototype.set
标识为第一个读取集,然后将其作为函数调用。 这是否意味着在我在原始代码(最上面)中编写的设置陷阱中,没有拦截对映射属性的修改/设置,事实上,使用了映射的隐式/本机-
Map.prototype.set
,而不是我们通过代理授予的
Reflect.set


所有这些不都进一步强化了代理和映射不能很好地混合的事实吗?我走错方向了吗?如果是这样,我会误解什么?代理应该像对待任何其他对象一样对待地图吗?

这不是bug,而是特性(笑话)

您应该了解代理的.get和.set的具体操作。Get将拦截对象的任何读取尝试。让我们举个例子:

///--While the following---//
let m = new Map();
m.set('tray', ']')
m.tray //undefined
在第一行,我们:从名为set的对象属性中读取,然后尝试将其作为函数调用

在第二行,我们从名为get的对象属性中读取,然后尝试将其作为函数调用

如果要尝试此代码:

p.set(1,2)
p.get(1)
然后,您将尝试为名为val的目标设置5,setter将触发

这就是代理的setter和getter的工作方式

因此,要实现所需的行为,请检查属性名称并返回带有一些附加实现的函数。不要忘记调用原始函数

例如:

p.val = 5;
希望这有帮助

更新:

让obj={
取:(v)=>v
};
让处理程序={
get:(目标,关键点)=>{
如果(键=='take'){
返回函数(v){
log(`logger说:函数${key}是用参数${v}`调用的);
}
返回目标[键];
}
}
};
让proxy=newproxy(obj,handler);
代理(5);

委托书(3)
这是否间接说明代理API不适用于映射,还是说当映射被代理时,设置陷阱没有任何用途?因为老实说,我觉得这有点难看。不,不是。让我们拿这个对象:{take:(v)=>v};我们该怎么办?在代理上创建take方法?不,我们会用代理的方式来代理。我认为相同的名字(set/set)让你困惑。谢谢你的更新,但这并不能回答我的问题。让我重述一下我问的关于设置陷阱的目的的问题;当Map_uu被代理时,设置陷阱中是否有任何用途?据我所知,根据MDN,set陷阱应该拦截任何修改目标对象的操作,这一行->
if(k==='set')返回函数(v){Reflect.set(o,k,v)}
使其在代理贴图时看起来像,set陷阱没有任何用途,因为即使拦截修改目标obj的
Map.prototype.set
也是通过
get
陷阱完成的。我认为正确的答案是:它取决于每个实现,应该避免依赖于此。
get: (o, k) => {
 if (k==='get') return Reflect.get(o, k).bind(o);
if (k==='set') return function(v){Reflect.set(o, k, v)}
}