JavaScript Proxy未按预期工作:in操作符执行结果异常问询
嘿,我来帮你拆解这个Proxy has陷阱的问题,搞清楚为什么输出和预期不一样~
首先先把你的代码格式化一下,看起来更清晰:
var foo = new Proxy({x:20,y:20},{ has: function(target, prop) { console.log(target.hasOwnProperty(prop)) // 这里输出false if(target.hasOwnProperty(prop)){ return true; } return false; } }); console.log('toString' in foo) // 这里输出true
核心原因:in操作符会检查原型链,Proxy的has陷阱返回false不代表最终结果就是false
你遇到的情况可以拆成两步看:
- 当执行
'toString' in foo时,触发Proxy的has陷阱,传入的prop是'toString'。目标对象{x:20,y:20}自身并没有toString属性,所以target.hasOwnProperty(prop)返回false,这就是第一个控制台输出的false。 - 你的
has陷阱因为条件不满足,返回了false。但这里有个关键细节:如果Proxy的has陷阱返回false,JavaScript引擎并不会直接判定属性不存在,它会继续去目标对象的原型链上查找。而目标对象的原型是Object.prototype,这个原型上自带toString方法,所以最终'toString' in foo会返回true,也就是第二个控制台输出的内容。
为什么有人说“正常应输出两次false”?
那是因为他们可能假设了目标对象是不可扩展的。当目标对象被设置为不可扩展时,引擎会遵循has陷阱的返回值,不再去原型链查找。比如修改代码成这样:
var target = {x:20,y:20}; Object.preventExtensions(target); // 把目标对象设为不可扩展 var foo = new Proxy(target, { has: function(target, prop) { console.log(target.hasOwnProperty(prop)); // 输出false return target.hasOwnProperty(prop); } }); console.log('toString' in foo); // 输出false
这时候控制台就会输出两次false,因为目标对象不可扩展,引擎不会再去原型链找toString了。
如果你想让'toString' in foo返回false(不依赖原型链)
除了把目标对象设为不可扩展,你也可以在has陷阱里直接拦截所有原型链属性的检查,比如:
var foo = new Proxy({x:20,y:20},{ has: function(target, prop) { const hasOwn = target.hasOwnProperty(prop); console.log(hasOwn); // 只返回自身属性的存在性,忽略原型链 return hasOwn; }, // 可选:如果还要拦截get操作,避免原型属性被访问到 get(target, prop) { if (target.hasOwnProperty(prop)) { return target[prop]; } return undefined; } }); console.log('toString' in foo); // false
内容的提问来源于stack exchange,提问作者Ben Rivers
相关产品推荐
相关产品推荐

