Emulating "Private" Variables in JavaScript with Closures and Factory Functions

Some Dood on November 16, 2018

Despite the recent implementation of classes in JavaScript, there has never been a native way of controlling the visibility of an object's proper... [Read Full]
markdown guide
 

The one place where I never particularly liked this method personally is where the type of the object is also relevant - with your factory, each object is it's own thing, not using any sort of prototypical inheritance or the like.

For the times where I find it necessary to actually use truly private variables and still take advantage of JavaScript's built-in inheritance, there's also the WeakMap:

let NamedThing = (function() {
  const Private = new WeakMap();
  return class NamedThing {
    constructor(name) {
      // Yes, we're only storing one value in the "private object".
      // Of course, the example is a bit contrived.
      Private.set(this, { name });
    }

    // For comparison to the original. I'd use 'get name()' and 
    // 'set name(name)' instead, personally, but that I think is more
    // a matter of personal preference.
    getName() { return Private.get(this).name; }
    setName(name) { Private.get(this).name = name; }
  }
})();

let Animal = (function(NamedThing) {
  const Private = new WeakMap();
  return class Animal extends NamedThing {
    constructor(name, job) {
      super(name);
      Private.set(this, { job });
    }
    getJob() { return Private.get(this).job; }
    setJob(job) { Private.get(this).job = job; }

    // Just for exposition: this should always return undefined,
    // since NamedThing has it's own WeakMap, separate from this one
    getNameFromHere() { return Private.get(this).name; }
  }
})(NamedThing);

const presto = new Animal('Presto', 'Digger');
console.log(presto instanceof NamedThing); // true
console.log(presto.getName());             // Presto
console.log(presto.name);                  // undefined
console.log(presto.getNameFromHere())      // undefined
console.log(presto instanceof Animal);     // true
console.log(presto.getJob());              // Digger
presto.setJob('Bone Finder');
console.log(presto.getJob());              // Bone Finder

Of course, if IE <11 support is something you care about, this isn't viable (even after being fed through Babel) unless leaking memory is OK with you.

 

I like how clever this is. Surely, this has its uses, but for me, it's too much of a price to pay just to enable inheritance. It's one big soup of JavaScript obscurities (like how classes can be passed in as arguments to a function). I can imagine in my head how a traditional object-oriented developer would look at this and be like, "WHAT IS THIS??? JAVASCRIPT IS A HORRIBLE LANGUAGE!"

 

It depends on how important inheritance is for your use case. And while I haven't gone looking, I bet the Babel plugin for #name likely does much the same thing.

 

I wonder what the memory performance is like compared to this:

const privates = new WeakMap()
class Animal {
  constructor(name, job) {
    privates.set(this, { name, job })
    this.aPublicOne = true
  }

  // Real Getters
  get name() {
    return privates.get(this).name
  }
  get job() {
    return privates.get(this).job
  }
  // Real Setters
  set name(name) {
    privates.get(this).name = name
  }
  set job(job) {
    privates.get(this).job = job
  }
}

Liek, I know instantiating closures isn't the same as actually declaring separate different functions. But it also is more expensive than object methods, to my great disdain.
Will this be somewhere in the middle, or actually worse than both?

 

I'm not sure myself, honestly. I'd love to know. When I have the time, I'll try to create a rigorous experiment for this using the DevTools Memory tools.

If I were to make an educated guess, I'd say the difference in memory efficiency would be negligible.

 

How funny is it, though, that this method is still using closures, the 5 functions capturing privates :D

It makes you realize that even though closures are so ubiquitous in JavaScript, not everyone truly understands it.

 

I have been practising Factory Functions for a while in this repo
github.com/swarupkm/practise-js/tr...

The same I have done in Java as typical Object Oriented.

In this link medium.freecodecamp.org/class-vs-f... I found this quotations

I think Class Free Object Oriented Programming is JavaScript’s gift to humanity.
— Douglas Crockford “The Better Parts”

 

Douglas Crockford truly is the legend of JavaScript. I totally agree with that quote.

I bet I would go insane if I needed to write a class for every time I needed to instantiate objects. Just imagine the hassle it would be to pass in an object as an argument to a function if classes were required to instantiate that object.

// Method #1 and Method #2 achieve the exact same thing.

// METHOD #1
class Options {
  constructor(value, isWritable) {
    this.value = value;
    this.writable = isWritable;
  }
}

Object.defineProperty(window, 'dev', new Options('to', false));

// METHOD #2
Object.defineProperty(window, 'dev', {
  value: 'to',
  writable: false
});
 

That's actually similar to how options work in Rust.
You construct a struct.
If it's big, you often use a builder to not have to construct it all at once.
However, it all works out great in the end, and everyone is ecstatic :/

 

Has anyone tried something as naive as this?

The 101 smoke test worked, it seems like _flees are gonna be garbage collected, what could go wrong? You can also attach getters and setters and improve it quite more, make it readonly or writeonly, etc.

class Dog {
  constructor() {
    let _flees = 0;
    this.getFlees = () => _flees;
    this.setFlees = (f) => {_flees = f};
  }
}

const a = new Dog;
const b = new Dog;

a.setFlees(1);
b.setFlees(2);
console.log(a.getFlees());
console.log(b.getFlees());

a.setFlees(11);
b.setFlees(22);
console.log(a.getFlees());
console.log(b.getFlees());
// output 1 2 11 22

The obvious side effect of this simplicity is of that _flees won't be able to be accessed by other methods at all, they all have to use the accessor methods.

So they are super-private.

But is this a wrong thing necessarily? I'm only entertaining the idea, but unless one uses it in practice, one can't know really...

Any thoughts?

 

Honestly, I doubt that anyone has the time to add this level of complexity just for privacy and encapsulation in JavaScript. I wrote this post to inform people that it is indeed possible, albeit rather impractical. Most of us would just prefer using the _ naming convention to denote member privacy.

I wouldn't say it's a "wrong thing", per se. It's still a cool party trick and all, but if one hopes to use this in production code, they better hope that the next person maintaining their code knows enough about JavaScript to understand why all the boilerplate code is necessary for member privacy.

 

Nice article. Can I guess that you have been influenced by youtube.com/watch?v=ImwrezYhw4w ?

I have been influenced for sure, and I deeply appreciate the multi-paradigm possibility in JavaScript

 

Ooooooh! I am so glad to find a fellow fan of Fun Fun Function here. Unfortunately, no, I was not entirely influenced by the video. "Entirely". I did learn about the concept from that video, though.

The inspiration behind this article comes from a thought experiment I had while I was in my shower. I just wondered how to implement private variables in JavaScript and POOF! I made an article about it.

 

Yup, I am a big fan of Fun Fun Functions. Fluffykins is the word I keep hearing about in his videos , hence I thought you might know about it.

Factory Functions . I have recently started working on nodejs and previously I had background in Java, Python , Ruby and I followed traditional OOPS programming.

However by going through FFF videos, I am convinced to think functionally and create Objects that way. Ultimate goal is to createsOBJECTS whatever way it may be.

Implementation of Classes in JS feels like implementation of Functional Programming in Java. Basically they are retrofitting stuff.

This particular rant against classes by FFF was awesome. youtube.com/watch?v=Tllw4EPhLiQ&li...

Yes! Someone finally caught on with the Fluffykins reference. I've been using it in my code examples recently in my recent posts in the hopes of finding a fan of the show. You, my friend, are the first that I have found.

That is why I find JavaScript to be one of the best languages out there. It just finds a way to combine various paradigms, which makes you think differently about programming. Traditional programming makes you strictly think in a specific way. For me, it doesn't open my mind to new possibilities enough, which is why I grew to love JavaScript.

 
[deleted]
 

Prepending private variables with an underscore is a convention that has been used by c/c++ developers since the beginning of time. I still do it to the same effect but it is becoming less common with newer devs entering the workforce who may not have been exposed to this convention.

 

Interesting. Thank you for the insight.

As an older dev who has long grown past his C/C++ zenith, I can't say it was a convention I was ever exposed to in the workforce myself; surprisingly. Can't say I ever really bothered to look it up either. 😖 Sounds like I need to get out more. 😀

 

Despite the recent implementation of classes in JavaScript, there has never been a native way of controlling the visibility of an object's property.

Soon: Stage 3 proposal for private fields, available already in Babel.

 
code of conduct - report abuse