JavaScript Closures

A closure is like a backpack

Across my time studying JavaScript object-oriented programming, I’ve searched for and have been eluded a good, concise definition for closures. For every video or article I found on the subject that defined it, I could find another that seemingly differed from it in at least a slight way. Even the MDN definition — “A closure is the combination of a function and the lexical environment within which that function was declared” — is not exactly illuminating for beginners.

The Web Has Imprecise Definitions for a Closure

Across the web, the most common definition for closure in JavaScript I kept coming across is a function inside a function that uses data from the parent scope.

function personCalls(caller) {
return function(otherName) {
console.log(caller + ' calls ' + otherName + '.')
}
}
var johnCallsSomeone = personCalls('John') // returns function
johnCallsSomeone('George') // logs 'John calls George.'

The next most common is that a closure is any function that utilizes variables for preserving data.

function add(num1, num2) {
return num1 + num2
}

Both of the prior code examples are examples of closures, but they aren’t closures themselves. Anytime we create a function though, a closure is created at the definition time. Which begs the tantalizing question…

What exactly is a closure (in my thinking)?

A closure is the scope created in combination with lexical scoping that allows a function to access all visible variables at the time of its creation.

It remembers (closes over) its surrounding context (variables and scopes it can reach). Remember, it doesn’t remember values, but it remembers variables.

Common within all the definitions for closures, we notice that functions and lexical scoping rules are key to the concept.

What are the most important lexical scoping rules to recall?

  1. Functions create their own local scope.
  2. Variables defined in the outer scope can be accessed within an inner scope.
  3. Each time you execute a function it creates a new scope
var str = 'hi'     // accessible globally
function foo(){
 var s2 = ' world' // only accessible within foo
return str + s2 // foo can access str since it's in an outer scope
}
str = 'hello'
foo()              // what will it return?

If you said, ‘hello world’, you are correct. This proves that closures remember variables and not the specific values assigned to them when the closure was created. This feature can be incredibly powerful once you grok it.

What does this mean?

Closures let us encapsulate (read: hide) data, making it private and only accessible to/within the containing function and any functions created within that containing function. In the example above, only foo can access s2, which is a private variable.

In object-oriented programming, we can use functions, closures and objects to create objects with a private data only reachable via a public interface.

function myDay() {
var list = []
var date = new Date().toString()
return {
date: function(){return date},
add: function(task) {
list.push(task)
console.log('task added.')
},
logAll: function() {
list.forEach(function(task, idx) {
console.log((idx + 1) + ': ' + task)
})
}
}
}
var mar23 = myDay()
mar23.add('woke up')
mar23.add('brushed and showered')
mar23.add('ate cereal and milk')
mar23.date // returns 2019-03-23T09:39:48.976Z
mar23.logAll()
// logs:
// 1: woke up
// 2: brushed and showered
// 3: ate cereal and milk

Here I created an object factory function (myDay) that will allow me to collect everything I did in a day, remember the day the item was created, and log all the things added.

Within myDay I declared private variables for list and date . These can’t be used outside myDay. myDay also returns an object that has a public interface of 3 methods — logAll , add , and date . Since these properties are all assigned functions that were declared within myDay , they remember any variables visible (list & date) at the time of creation. Whenever I invoke .add on an object returned by myDay call. the function assigned to it remembers list via its closure, takes the argument passed to it and then adds it to the list array. Same with .date, within the function it remembers thedate private variable through its own respective closure and returns the object assigned to it. logAll accesses thelist private variable via its own closure too, sees the array and is able to iterate over it and log all items within it.

Take some time to chew it over. In order to understand closures, whenever you create a function, think over what its closure can see at that time and how that could augment your function.