Using WeakMap for Private Properties

This blog is about a cool idea of leveraging WeakMap to have private properties in Javascript Classes. A private property is a property that is only accessible to member functions of instances of the same class. Javascript inherently does not support private properties unlike languages such as Java or C++. It is however, at the time of writing, at Stage 0 Proposal to add it to the ECMAScript spec.

As a recap from my previous blog, a WeakMap is:

const myWeakMap = new WeakMap();
const harry = {};
const potter = () => {};
myWeakMap.set(harry, "cat");
myWeakMap.set(potter, 7);
myWeakMap.has(harry); // true
myWeakMap.get(potter); // 7
myWeakMap.delete(harry);

WeakMap Technique #

Traditionally, the way to have private properties in Javascript is to either prefix your variables or to encapsulate in a closure. Both of these methods do work, however they are either not restrictive enough (prefixes) or too restrictive (closures).

A WeakMap is similar to a HashMap but it allows objects as keys as well as not having a strong reference to its values (that’s why it’s called weak).

In the example below, we pass in an empty object into the WeakMap to hold all of the private properties of the class Wizard. To store the private properties, we also pass in the reference to the unique this object of the instance of the class Wizard as a key to the WeakMap.

const Wizard = (function() {
  const _private = new WeakMap();

  const internal = (key) => {
    // Initialize if not created
    if (!_private.has(key)) {
        _private.set(key, {});
    }
    // Return private properties object
    return _private.get(key);
  };

  class Wizard {
      constructor(name, house) {
          internal(this).name = name;
          internal(this).house = house;
      }

      getName() {
          return internal(this).name;
      }

      setName(name) {
          internal(this).name = name;
      }

      getHouse() {
          return internal(this).house;
      }

      setHouse(house) {
          internal(this).house = house;
      }
  }

  return Wizard;
}());

When we actually run this code, you can see on the second line that when we try to access the property _private the class returned does not have reference to it because of the IIFE. However internal class methods can still change the values under _private. So you can only change the properties within the Class by using its accessor methods such as get and set. In doing so, keeping the namespace hidden from all functions except members of the class effectively implements private properties.

const harrypotter = new Wizard('Harry Potter', 'Gryffindor');
console.log(harrypotter); // Wizard {}
console.log(harrypotter.getName()); // "Harry Potter"

harrypotter.setName('Arry Pottr');
console.log(harrypotter.getName()); // "Arry Pottr"

Sources:

 
38
Kudos
 
38
Kudos

Now read this

Web Workers 101

Do you want to know the basic “todo mvc” of the Web Workers API? This is not the end all of what there is to know about Web Workers, but rather this a good first guide to exploring the topic. The posts on MDN would be a great resource... Continue →