JavaScript Guidebook

JavaScript 完全知识体系

Proxy - handler.has

handler.has() 方法主要用于拦截 HasProperty 操作,即判断对象是否具有某个属性时,这个方法会生效,典型的操作就是 in 运算符。

语法

const proxy = new Proxy(target, {
has: function (target, property) {
// do something
},
});
参数说明类型
target目标对象object
property需要检查是否存在的属性string

说明

拦截

该方法会拦截目标对象的以下操作:

  • 属性查询:foo in proxy
  • 继承属性查询:foo in Object.create(proxy)
  • with 检查:with(proxy){(foo);}
  • Reflect.has()

约束

如果违背了以下的约束,proxy 会抛出 TypeError 异常:

  • 如果目标对象的某个属性本身不可被配置,则该属性不能够被代理隐藏
  • 如果目标对象为不可扩展对象,则该对象的属性不能够被代理隐藏

示例

以下代码演示如何拦截 in 操作符:

const proxy = new Proxy(
{},
{
has: function (target, prop) {
console.log('Called:' + prop);
return true;
},
}
);
console.log('foo' in proxy);
// "Called: foo"
// true

下面代码违反了约束:

const foo = { a: 10 };
Object.preventExtensions(foo);
const proxy = new Proxy(foo, {
has: function (target, prop) {
return false;
},
});
console.log('a' in proxy);
// Uncaught TypeError: 'has' on proxy: trap returned falsish for property 'a' but the proxy target is not extensible

隐藏某些属性不被发现

const handler = {
has(target, prop) {
if (key[0] === '_') {
return false;
}
return key in target;
},
};
const target = { _prop: 'foo', prop: 'foo' };
const proxy = new Proxy(target, handler);
console.log('_prop' in proxy);
// false

上面代码中,如果原对象的属性名的第一个字符是下划线,proxy.has 就会返回 false,从而不会被 in 运算符发现。

值得注意的是,has 方法拦截的是 HasProperty 操作,而不是 HasOwnProperty 操作,即 has 方法不判断一个属性是对象自身的属性,还是继承的属性。

另外,虽然 for...in 循环也用到了 in 运算符,但是 has 拦截对 for...in 循环不生效。