JavaScript Closures
A closure give you access to an outer function’s scope from an inner function outside of its original usage.
A Simple Example
As a simple example, let’s create the simplest closure we can possibly create. We’ll create a function nested inside another function:
function jump() {
var height = 10; function scream() {
console.log(height);
} scream();
}jump(); // logs 10
Here we have a function scream()
that has access to the scope of the function jump()
. This means that scream
has access to the height
variable.
Have we created a closure? Not just yet. This is part of the way there. Let’s change our jump
function to return the scream
function and expand on this by saving the jump
function to a new variable called newJump
.
function jump() {
var height = 10; function scream() {
console.log(height);
} return scream;
}var newJump = jump(); // function runs but doesnt log anything// you would think that now our code has run
// you would think that javascript has gotten rid of our height variable// but we can still use the newJump function as if our content was still intact
newJump(); // logs 10
Notice how we save the output of a function to a new variable. The jump
function ran and processed itself and we saved the contents to a new variable.What JavaScript does is keep a reference to that original scope and we are still able to use it and the height
variable. This reference is called closure.
Another Example
Let’s say we want to use a closure; we define a function (our inner function) b
inside another function (our outer function) a
and expose b
.
To expose b
, we simply return it or pass it into a
. b
will now have access to the variables within the scope of a
even after a
has been returned.
function add (a) {
return function (b) {
return a + b
};
}// use
var addUp7 = add(7)
var addUp14 = add(14)console.log (addUp7(8)); // 15
console.log (addUp14(12)); // 26
In the example above, we have defined a function add(a)
, which takes a single argument, a
, and returns a new function. The function it returns takes a single argument, b
, and returns the sum of a
and b
.
addUp7
and addUp14
are closures. It creates functions that can add a specific value to their argument. In the example above, add
is used to create two new functions — addUp7
and addUp14
which share the same function body definition but contain different lexical environments. In the lexical environment of addUp7
, a
is 7 while in addUp14
, a
is 14.
Although JavaScript does not have the built-in ability to declare methods as either public or private, it can emulate this functionality via closures:
var houseRent = (function() {
var rent = 100000;
function changeBy(amount) {
rent += amount;
}
return {
raise: function() {
changeBy(10000);
},
lower: function() {
changeBy(-10000);
},
currentAmount: function() {
return rent;
}
};
})();
alert(houseRent.currentAmount()); // $100,000
houseRent.raise();
houseRent.lower();
alert(houseRent.currentAmount()); // $100,000
houseRent.changeBy(20000) // TypeError: undefined is
not a function
Using closures to namespace private functions keeps more general namespaces clean, preventing naming collisions. Neither the rent
variable nor the changeBy
function is available outside of houseRent
. However, raise
, lower
and currentAmount
all have access to them and can be called on houseRent
.