Experiments in JavaScript Closures
I have been trying to improve the object-oriented nature of my JavaScript lately. Part of that process is getting a handle on closures and public/private data. The following are a few experiments to help me process these concepts, I am posting them in case they help someone else as well.
All of the experiments use a similar structure where I define a function that returns another function. The argument to the "creator" function is printed in the "created" function and should remain the same.
Experiment - 0
The first experiment is to show what I don't want to happen.
var index = 0; function builder(x){ index = x; return function(){ log(index); } } var two = builder(2); var one = builder(1); var zero = builder(0); zero(); one(); two();
This code prints the same value 0
for every call because the index
variable is the same for all functions.
Experiment - 1
We can see how this changes if we move the variable inside the first function declaration. Moving the variable does two things. First it scopes it to the builder
function. We can see this scoping by trying to print x outside of builder, as shown below.
function builder(index){ var x = index; return function(){ log(x); } } log(x);
This code throws an exception because x
isn't defined.
However, inside of builder
, x
is defined and it is included in the closure for the function that builder returns. That means it remembers its value.
function builder(index){ var x = index; return function(){ log(x); } } var two = builder(2); var one = builder(1); var zero = builder(0); zero(); one(); two();
I create the functions in the opposite order that I call them in, just to be sure that I am not just getting lucky.
Experiment - 2
So the inner function remembers the value of a variable from the parent scope, what about the argument to the parent function.
function builder(index){ return function(){ log(index); } } var two = builder(2); var one = builder(1); var zero = builder(0); zero(); one(); two();
As we would expect, the arguments are remembered in the same way that the variable is.
Experiment - 3
The last experiment uses a constructor. This one is fairly straight forward and did exactly what I expected. Values assigned to this
are remembered on the object, whew.
function Builder(index){ this.value = index; this.printValue = function(){ log(this.value); }; } var two = new Builder(2); var one = new Builder(1); var zero = new Builder(0); zero.printValue(); one.printValue(); two.printValue();