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. ↩︎

License: CC-BY-4.0