Prehistory
One of the biggest omissions in
JavaScript is the impossibility of creating private fields in user types. There is only one good way to create a private variable inside the constructor and create privileged methods that will have access to them, for example:
function Person(name) { this.getName = function() { return name; }; }
In this example, the
getName () method uses the
name argument (which is in fact a local variable) to return the value of the person’s name without expanding the
name as a property of the object. This approach is quite suitable for itself, but very inefficient in terms of performance. As you know, functions in
JavaScript are objects and if you use more instances of a Person object, each will store its own copy of the
getName () method, instead of using just one of the prototype.
As an alternative solution, you can choose the way to create a field private by agreement, making a prefix in its name, usually in the form of underscores. The underlining is not magic, it does not protect the field from use, rather just a reminder that it is not worth touching. For example:
function Person(name) { this._name = name; } Person.prototype.getName = function() { return this._name; };
This pattern is more effective since each instance will use the same method from the prototype. The method, like the field, is accessible from the outside; all that we have done is agreed that
you cannot touch
._name . This solution is far from ideal, but a rather large number of programmers use it. At one time it came to us from
Python .
')
There is another option when we use a common field for all instances, which can be easily created using the
IIFE function, which contains a constructor. For example:
var Person = (function() { var sharedName; function Person(name) { sharedName = name; } Person.prototype.getName = function() { return sharedName; }; return Person; }());
Here,
sharedName is common to all instances of
Person , and each new instance will overwrite the value with the
name argument. This is obviously not a meaningful solution, but very important in the way of understanding how we can implement truly private fields.
On the way to private fields
The shared private field pattern indicates a potential solution: what if the private data is not stored in the instance, but will have access to it? What if there is an object that can keep hidden fields away and hide all private information about the implementation? Before
ECMAScript 6, you probably would have implemented it like this:
var Person = (function() { var privateData = {}, privateId = 0; function Person(name) { Object.defineProperty(this, "_id", { value: privateId++ }); privateData[this._id] = { name: name }; } Person.prototype.getName = function() { return privateData[this._id].name; }; return Person; }());
In this way, we have come to something like this :) The
privateData object
is not accessible from outside
IIFE , it completely hides all the information stored inside. The variable
privateId stores the next available ID that the instance uses. Unfortunately, the ID has to be stored in the instance and you should make sure that it is also not available during use. Therefore, we use
Object.defineProperty () to set the value and to make sure that the variable is read only. Then inside
getName () , the method accesses private variables using
_id , for reading and writing.
This approach is good, quite suitable for storing private variables. But the extra use of
_id is only part of the trouble. This approach also causes problems - even if the instance is deleted by the garbage collector, the data that he wrote to
privateData will remain in memory. Anyway, it is the best that we can implement in
ECMAScript 5 .
WeakMap output

WeakMap solves the remaining problems of the previous example. First, we don’t have to store a unique ID anymore, since the instance itself can be a unique ID. Secondly, the garbage collector will be able to remove the record that we no longer need, since WeakMap is a collection with weak links. After the instance is deleted, the entry will not have hard links. The garbage collector in this case takes away from the life of all the records that were associated with this instance. Exactly the same basic pattern from the previous example, but more kosher:
var Person = (function() { var privateData = new WeakMap(); function Person(name) { privateData.set(this, { name: name }); } Person.prototype.getName = function() { return privateData.get(this).name; }; return Person; }());
In this example, the
privateData is an instance of
WeakMap . When a new Person is created, a new record is added to WeakMap to store private variables. The key in
WeakMap is
this , although the developer can access an instance of a
Person object, he cannot access
privateData from outside this instance. Any method that wants to access this data simply transfers its instance (within which the method is located). In this example,
getName () gets an entry and returns the
name property.
Conclusion
This can be a great example for people who have not found the use of the new
WeakMap object in
ECMAScript 6 . Many predict future changes in the way we write JavaScript code. For me personally, this is a kind of a turning point in the power of
OOP JavaScript .