Hiding properties in JS… for real

Sometimes, you want to hide the property of an object1. Probably you are a library author and you are afraid that:

So here is what you do:

const protectedObj = Object.defineProperty({}, 'foo', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: 'hi there'
});
console.log(protectedObj.foo); // 'hi there'
console.log(Object.keys(protectedObj)); // []

Mission accomplished!
Well, nope, of course not.

JavaScript provides your users with Object.getOwnPropertyNames() or Reflect.ownKeys(), which will reveal the property nevertheless:

console.log(Object.getOwnPropertyNames(protectedObj)); // [ 'foo' ]
console.log(Reflect.ownKeys(protectedObj)); // [ 'foo' ]

You should probably leave it at that, because if your users are using these, they know what to expect.
But anyway, here is a funny trick that puzzled me for a moment a few days ago.

Proxy to the rescue

The trick to really hide properties is to use Proxy. The idea is that you set a trap, a function that is executed when the user tries to run Object.getOwnPropertyNames() or Reflect.ownKeys(), instead of whatever the JavaScript engine is doing internally. And you decide what the function returns - or in this case, doesn’t.

const hardProtectedObj = new Proxy({
    foo: 'hi there',
}, {
    ownKeys: (target) => {
        return [];
    },
});
console.log(hardProtectedObj.foo); // 'hi there'
console.log(Object.keys(hardProtectedObj)); // []
console.log(Object.getOwnPropertyNames(hardProtectedObj)); // []
console.log(Reflect.ownKeys(hardProtectedObj)); // []

I believe this is the ultimate solution, until JavaScript gets friend classes. On the other hand…


1 I assume that in this case you can’t use an IIFE because other parts of your library need to access these properties.

Tags: JavaScript proxy