Closures - Local vs Private ?


#1

Hey,

When I read about Closures, it’s often said that we are using Closures to create private variable, that cannot be accessed outside the function.
But isn’t it that this is true for all local variables inside a function? That they cannot be accessed outside the function?

In regards of Closures, what is the difference between a local and a private variable?

Thanks


#2

Its true. And that’s part of the reason the road from closures lead to this path where people start talking about privates.

As far as OOP goes, JavaScript doesn’t support private variables in classes. All member variables get attached to an instance are exposed and available for anyone outside of the class to see and use however they see fit.

class Person {
  constructor (name) {
    this.name = name; // always public
  }
  sayName () {
    console.log(`I'm ${this.name}`);
  }
}
const ann = new Person('Ann');
ann.sayName(); // 'I'm Ann'
console.log(ann.name); // 'Ann'

But privacy and encapsulation is one of the pillars of OOP. How can we get that in our classes when the language doesn’t even support it?! Wait a minute… local variables inside functions are “private” since they can’t be accessed outside of the function in which they’re created. And our class constructor is a function… What if we used closures to maintain privacy of our class variables?? And we can! Here’s the name-private version of Person:

class Person {
  constructor (name) {
    this.sayName = () => {
    	console.log(`I'm ${name}`);
    }
  }
}
const bob = new Person('Bob');
bob.sayName(); // 'I'm Bob'
console.log(bob.name); // undefined

Here, the name “property” of the Person instance is the closure variable passed in to the constructor. For this to be accessible from within class methods, those methods need to also be created within the constructor scope which is why sayName is defined the way it is now. Here it becomes a closure that is able to access name from the parent scope, the constructor call. This means you’re copying functions for every instance created rather than letting them be shared like normal, but them’s the breaks for getting privacy.

I think the class example is the best way to show privacy because it’s the kind of place a lot of programmers expect privacy like this to exist, but you can also apply this to simpler situations like counter factories:

function createCounter () {
  let counter = 0;
  return () => ++counter;
}

const counterA = createCounter();
console.log(counterA()); // 1
console.log(counterA()); // 2
console.log(counterA()); // 3 
const counterB = createCounter();
console.log(counterB()); // 1
console.log(counterB()); // 2
console.log(counterA()); // 4 

Here, we’re creating functions (closures) which contains a hidden property counter that gets incremented when the function is called. There’s no way to access the variable directly, but it’s value is returned as a result of the call. It’s almost like having a class instance that has one variable and one method call but you only have access to the method and nothing else, not even the class instance itself. Still, you can tell by using the function that there is some data being retained and used to get the results your seeing. It’s that magical private variable.