JavaScript Proxy has Trap and the in Operator
The has trap in a JavaScript Proxy handler
provides a way to intercept and customize property existence checks.
When code checks whether an object contains a specific property using
the in operator or Reflect.has(), the
Proxy routes the evaluation through the
handler.has() method. This allows developers to hide
existing properties, emulate the presence of dynamic keys, or enforce
custom validation rules during property lookups.
Syntax and Parameters
The has method takes two arguments:
const handler = {
has(target, prop) {
// Custom logic
return true; // Must return a boolean
}
};target: The original target object wrapped by the proxy.prop: A string orSymbolrepresenting the property name being checked.
The method must return a boolean value indicating whether the property exists on the target or virtual object.
Intercepted Operations
The has trap intercepts the following operations:
- The
inoperator:'foo' in proxy - Reflect API:
Reflect.has(proxy, 'foo') withstatements:with (proxy) { (foo); }
Practical Example: Hiding Private Properties
A common use case is preventing callers from detecting “private”
properties, such as keys prefixed with an underscore
(_).
const targetObject = {
id: 101,
_internalToken: "secret_abc123",
username: "johndoe"
};
const handler = {
has(target, prop) {
// Hide properties starting with an underscore
if (typeof prop === "string" && prop.startsWith("_")) {
return false;
}
// Delegate normal existence check to the target
return prop in target;
}
};
const proxy = new Proxy(targetObject, handler);
console.log("username" in proxy); // true
console.log("_internalToken" in proxy); // false
console.log(Reflect.has(proxy, "id")); // trueIn this example, the proxy returns false for
_internalToken, even though the property physically exists
on targetObject.
Invariants and Constraints
JavaScript enforces specific invariants that the has
trap cannot bypass:
- Non-configurable properties: If a property exists
on the target object as a non-configurable own property, the
hastrap cannot returnfalse. - Non-extensible objects: If a property exists on a
target object that is non-extensible (via
Object.preventExtensions()), the trap cannot returnfalse.
Violating these invariants will cause the runtime to throw a
TypeError.
Difference
from Object.hasOwn and hasOwnProperty
The has trap only intercepts operations checking the
entire prototype chain (like in). Methods like
Object.hasOwn(proxy, prop) or
proxy.hasOwnProperty(prop) do not trigger the
has trap; instead, they trigger the
getOwnPropertyDescriptor trap.