Object.X() Handlers

Handlers for Object.X() Methods

The remaining traps back the reflective Object methods. ownKeys feeds Object.keys() and JSON.stringify(), getOwnPropertyDescriptor and defineProperty handle the descriptors of Descriptors and Freezing, and getPrototypeOf answers instanceof.

Hiding keys from reflection and faking a prototypeJavaScriptLive
const hidePrivate = (obj) => new Proxy(obj, {
  ownKeys: (t) => Reflect.ownKeys(t).filter((k) => !String(k).startsWith("_")),
  getOwnPropertyDescriptor: (t, k) =>
    String(k).startsWith("_") ? undefined : Reflect.getOwnPropertyDescriptor(t, k),
  defineProperty(t, k, desc) {
    console.log(`define ${k}`);
    return Reflect.defineProperty(t, k, desc);
  },
  getPrototypeOf: () => Array.prototype,
});
const rec = hidePrivate({ id: 7, _secret: "s3" });
rec.total = 10;                                   // [[Set]] ends in [[DefineOwnProperty]]
console.log(Object.keys(rec), JSON.stringify(rec), rec instanceof Array);
console.log(Object.getOwnPropertyDescriptor(rec, "_secret"));

The engine enforces invariants: for a non-extensible target, ownKeys must list exactly its keys and getPrototypeOf its real prototype, or TypeError is thrown. Proxies also break internal slots and #private fields: new Proxy(new Map(), {}).size throws because the getter receives the proxy, not the map.