Hiding Property Existence Using the has Trap

The in operator determines whether a property exists on a given object and returns true if there is either an own property or a prototype property matching the name or symbol. For example:

  1. let target = {
  2. value: 42;
  3. }
  4. console.log("value" in target); // true
  5. console.log("toString" in target); // true

Both value and toString exist on object, so in both cases the in operator returns true. The value property is an own property while toString is a prototype property (inherited from Object). Proxies allow you to intercept this operation and return a different value for in with the has trap.

The has trap is called whenever the in operator is used. When called, two arguments are passed to the has trap:

  1. trapTarget - the object the property is read from (the proxy’s target)
  2. key - the property key (string or symbol) to check

The Reflect.has() method accepts these same arguments and returns the default response for the in operator. Using the has trap and Reflect.has() allows you to alter the behavior of in for some properties while falling back to default behavior for others. For instance, suppose you just want to hide the value property. You can do so like this:

  1. let target = {
  2. name: "target",
  3. value: 42
  4. };
  5. let proxy = new Proxy(target, {
  6. has(trapTarget, key) {
  7. if (key === "value") {
  8. return false;
  9. } else {
  10. return Reflect.has(trapTarget, key);
  11. }
  12. }
  13. });
  14. console.log("value" in proxy); // false
  15. console.log("name" in proxy); // true
  16. console.log("toString" in proxy); // true

The has trap for proxy checks to see if key is "value" returns false if so. Otherwise, the default behavior is used via a call to the Reflect.has() method. As a result, the in operator returns false for the value property even though value actually exists on the target. The other properties, name and toString, correctly return true when used with the in operator.