Hiding properties in JavaScript

Sometimes, you want to define a property on an object that can’t easily be accessed by code you didn’t write.

There are several ways to create what might be called “hidden properties”, without looking at things like variables closed by closures, which are limited by scoping rules.

Now-classic, the non-enumerable property

You can use Object.defineProperty to create properties that are not marked enumerable . This makes the property not show up when you enumerate the object's properties with certain methods, such as the for ... in loop and the Object.keys function.

However, you can still find it using the Object.getOwnPropertyNames function, which returns even non-enumerable properties. And of course, you could still access the property by its key, which is just a string that anyone can build, in theory.

Notes

Property is not actually hidden, it just doesn’t appear in some lists of properties. There is no real convention for which properties should be non-enumerable, and which shouldn’t. Someone seeing the property during runtime inspection will not necessarily know it’s supposed to be hidden or that it’s non-enumerable.

A (non-enumerable) symbol property

In ES6, it’s possible to make properties with keys of a new primitive type — symbol . This type is used by Javascript itself to enumerate an object using a for ... of loop and by library writers to do all kinds of other things.

Symbols have a descriptive text, but they are reference types that have a unique identity. They aren't like strings, which are equal if they have the same value. For two symbols to be equal, they must be two references for exactly the same thing.

You create a symbol using the Symbol function:

You can use the Object.defineProperty function to define properties with symbols as keys.

Unless someone gets a reference to that exact symbol object, they can’t look up the value of the property by key.

But you can also use the regular syntax:

Properties with this key type will never show up in for ... in loops or the like, but can still be enumerable and non-enumerable, as functions like Object.assign work differently for non-enumerable properties.

Object.getOwnPropertyNames won't get you the symbol keys of the object, but the similarly named Object.getOwnPropertySymbols will do the trick.

Notes

The property is not totally hidden. You can still get the symbol key using specialized methods. Someone inspecting the object at runtime will be able tell the property is supposed to be hidden. Symbol properties are generally reserved for implementation details that people shouldn’t touch. Requires support for ES2015 to work.

Weak maps

The strongest way to hide a property on an object is not to store it on the object at all. Before ES6, this was kind of tricky to do, but now we have weak maps.

A weak map is basically a Map , i.e. a key-value store, that doesn't keep (strong) references to the keys so they can be garbage collected. A weak map is very limited, and doesn't allow you to enumerate its keys (this is by design). However, if you get a reference to one of the map's keys, you can get the value that goes with it.

They are primarily designed to allow extending objects without actually modifying them.

The basic idea is to create a weak map:

And use objects you want to extend as keys. Then the values would be sets of properties, either in the form of {} objects, or in the form of Map data structures.

The advantage of this approach is that someone needs to get a reference to your weakMap instance and the key in order to get the values out, or even know they exist There's no way around that. So it's 100%, guaranteed to be secure. Hiding properties in this way ensures no user will ever discover them and your web application will never be hacked.*

Notes

Totally hidden. You need a reference to the weak map to recover the property’s value. Not an actual property, so it doesn’t participate in the prototype chain and the like. Requires ES2015 to work.

(*) This is a lie.