Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the in operator return false for a Proxy property, but the property is still accessible in JavaScript?

Tags:

javascript

I’m trying to use a JavaScript Proxy to hide a property from detection while keeping it in the target object. The has trap successfully makes 'secret' in proxy return false, but the property is still accessible directly.

Code Example:

const target = { secret: 123, public: 456 };
const proxy = new Proxy(target, {
  has(t, prop) {
    if (prop === 'secret') return false; // Hide from `in` checks
    return prop in t;
  }
});

console.log('secret' in proxy); 
console.log(proxy.secret);      

Questions:

  1. Why does the in operator not block direct access to the property?
  2. How can I fully hide a property in a Proxy so it’s undetectable and inaccessible?
  3. Are there specific traps (e.g., get, ownKeys) that must be implemented together for consistency?

Observed Behavior:

  • 'secret' in proxy correctly returns false.
  • proxy.secret still returns the value 123.

Expected Behavior:
If the in operator returns false for 'secret', accessing proxy.secret should throw an error or return undefined.

Attempts to Fix:

  1. Tried using only the has trap.
  2. Researched other traps like get and ownKeys but unsure how to coordinate them.
like image 869
Yash Sanghvi Avatar asked Nov 17 '25 06:11

Yash Sanghvi


1 Answers

Yes, you need to coordinate the all related traps, you could make a generic function to hide object keys.

Note that in looks in the prototype chain so for handling class instances with inheritance there could be more complex logic required.

const hideKeys = (target, keys) => {
  keys = new Set(keys);
  return new Proxy(target, {
    get(t, prop){
      if(keys.has(prop)) return;
      return Reflect.get(...arguments)
    },
    has(t, prop) {
      if (keys.has(prop)) return false; // Hide from `in` checks
      return Reflect.has(...arguments);
    },
    ownKeys(){
      return Reflect.ownKeys(...arguments).filter(key => !keys.has(key));
    },
    getOwnPropertyDescriptor(t, prop){
      if(keys.has(prop)) return;
      return Reflect.getOwnPropertyDescriptor(...arguments);
    }
  });
}

const target = { secret: 123, public: 456 };

const proxy = hideKeys(target, ['secret']);

console.log('secret' in proxy);
console.log(Object.hasOwn(proxy, 'secret'));
for(const k in proxy){
  console.log(k);
}
console.log(proxy.propertyIsEnumerable('secret'));
console.log(proxy.secret);
console.log(JSON.stringify(proxy));
like image 73
Alexander Nenashev Avatar answered Nov 18 '25 19:11

Alexander Nenashev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!