Blog Articles

Data-hiding in ES6 (JavaScript) from an Object Oriented perspective

For a long time during my early career, I was an OO — object oriented — developer. I genuflected regularly in front of the altar of data encapsulation, object hierarchies and static typing. And the syntax. Oh the syntax!

But I have changed, of course, and so much of the dogma and ceremony that I participated in during those times has come to seem a lot less important than it was 20 years ago. Languages, and developers evolve. But that doesn’t mean there aren’t some really good lessons to learn.

Take, for instance, data encapsulation.

When I first began to seriously look at JavaScript as a language, data encapsulation – or the lack of it – was one of the things that really stuck in my old OO craw. While I loved the simplicity of the {} data structure, I hated the fact that most properties I chose to add to it were typically just there – sticking out for everyone to see and perhaps corrupt. The language didn’t make it very easy to keep this data protected. How do we handle this?

Take a look at how this simplistic approach to the {} data structure might cause some real headaches. Here we have a productCatalog() lookup function that returns a Product data object. It might look something like this:

Notice that the object returned here contains a function, related() which will find the set of products related to this one using this object’s id or name property. But those properties are just there hanging on to the returned object by their fingernails. What if some evil bit of code came along and did this: product.id = 0x00034 just to see what would happen? How would the related() function handle that? We just don’t know.

There are ways to deal with this of course. One of the great things about JavaScript is how flexible it can be. Maybe the developer who wrote the productCatalog() function knew some of these tricks. Here’s one way to handle it using Javascript’s Object.defineProperty function.

What I’d really like is for the Product object to have a reference to the id but no way for client code to read it or even see it. Closures, for example, provide a way to do this. But that’s really an entirely separate blog post, and what I really want to talk about here is ES6.

ECMAScript 2015

ES6 or ECMAScript 2015, as it is formally known, introduces lots of great new language features. I wish I had time to tell you about them all, but for now, I’ll just focus on one subject. Data Hiding and Encapsulation.

There are a few new ways developers can approach this problem now, when using modern JavaScript interpreters with ES6 features available.

Everything you need to grow your career.

Getters

First let’s take a look at Getters. ES6 getters allow you to easily use a function that makes a property read only. And since a getter is a function, the value could even be the result of some calculation. But that’s not the point here.

Here’s how you would use a getter in ES6 and how you could achieve the same functionality in ES5. The new syntax is way better.

But this still doesn’t really get what we want. There are two tools besides closures we can use to really and truly hide our data. Those are WeakMap and Symbol. Let’s look at the WeakMap first.

WeakMaps

The WeakMap is a new data structure in ES6. It acts a lot like a regular map data structure. They are iterable, and have getters and setters for objects. What makes them unique is that the keys are weakly referenced. This means, essentially, that when the only remaining reference to the key is the key itself, the entry is removed from the map. Here’s how you can use the WeakMap data structure to effectively hide private class data.

Assuming this code is in a module that exports the productCatalog function, there is no way for client code to see or modify the id property. Success!

I like this approach. It’s elegant and simple. The only real drawback I have found with this is performance. It’s pretty expensive to do these WeakMap lookups to get a handle on a property. So if performance is paramount. Consider using Symbol as property keys.

Symbols

I have found that using properties whose keys are Symbols, while not as elegant as WeakMap in my opinion is my preferred data hiding technique, because it’s just so much faster.

One of the interesting things about Symbol is that each Symbol is unique. If we can keep the Symbol private within our module,
then we don’t have to worry about client code accessing the property. Here’s how our Product object would look if we took this approach.

Additionally, when you use a Symbol for a property key, the property does not appear in the list of properties returned fromObject.getOwnPropertyNames(). This is nice. The downside is that the property leaks when using Reflect.ownKeys() or Object.getOwnPropertySymbols().

But I can live with that when performance matters. For Fidelity, we found that moving from WeakMap to Symbol for private data gave us a measurable, and quite significant performance boost. It’s not ideal that the properties are visible. But since they are
inaccessible, I’ll not worry about it too much.

Join the Red Hat Developer Program (it’s free) and get access to related cheat sheets, books, and product downloads.