DEV Community

loading...
Cover image for  You can't understand JavaScript without mastering Closure

You can't understand JavaScript without mastering Closure

albert_hadacek profile image Albert Hadacek ・3 min read

Closure is one of the features of the language that many programmers struggle to wrap their heads around. Yet, it is one of the core building stones of JS and a frequent topic that appears in coding interviews. In this article, you will learn all about it.

What happens when you call a function?

To understand closure, we need to fully understand how a JavaScript program works. Our code is interpreted line by line. Variables are stored in the global memory and we have a single execution thread.

When the interpreter reaches a function invocation the function is placed on the call stack and a new execution context is created for the function - it has its local memory and thread of execution. Think of it as a mini-program. When the function returns, either explicitly (reaching a return statement) or implicitly (by default functions return undefined), the function leaves the call stack and its execution context is destroyed.

What the heck is Closure?

Imagine this piece of code.


let name = "John"

function greet() {
  const greeting = "Hi"

  function printHi() {
    console.log(greeting + ' ' + name)
  }
  printHi()
}

name = "Jane"

greet() // "Hi Jane"

Enter fullscreen mode Exit fullscreen mode

Our inner function printHi has access to the local memory of its parent (greet) and the global memory. Notice, that we actually have access to the "fresh" data that is available during the call, not the declaration. That is how lexical scoping works in JavaScript.

But what would happen if we return a function instead of just calling it within the body of the outer function. Well, here the magic comes. A returned function from another function is not just a simple function definition, it is the definition plus the variables it has access to and needs to run stored in a backpack that comes with it.

What we just described is the mysterious closure. Formally, a closure is a when function remembers its lexical scope (the backpack) even when the function is called outside of that lexical scope.


function creator(num) {
  return function() {
    num = num * 2
    console.log(num)
  }
}

const double = creator(5)
double() //10
double() //20

const double2 = creator(7)
double2() // 14
double2() //28

double() // 40

Enter fullscreen mode Exit fullscreen mode

As we can see in the snippet above, whenever we call double it updates the same piece of data (num from its parent function) that is stored in its backpack, which is technically the hidden [[scope]] property the function has.

If you are wondering why is it useful, check the examples below.

Module pattern

The closure allows us to protect or hide certain pieces of information. The backpack is a hidden property so we can't just access it and update it as we would do with a standard object literal. It is also important to mention, that we can return a set of functions stored on an object and they would all be closures.

In the snippet below we are taking advantage of the so-called IIFE (Immediately Invoked Function Expression) which allows us to eliminate the middle step of calling the outer function as we do it directly when assigning it.


const myModule  = (function(){
  const apiKey = "123456789"

  return {
    displayKey() {
      console.log(apiKey)
    }
  } 
})()

myModule.displayKey() // "123456789"

Enter fullscreen mode Exit fullscreen mode

If we expose this module to another programmer, the API we prepared for him, does not allow him to change the key, he can only see it and there is no way he or she could change it other than rewriting it in the source code.

Basic caching and memoization

Imagine you would like to create a simple generator of IDs. To make sure you always return a number that is higher than the previous one, you can use closure. We will cache the value of the highest id in our current variable.


const newID = (function() {
  let current = 0
  return function() {
    return ++current
  }
})()

newID() // 1
newID() // 2

Enter fullscreen mode Exit fullscreen mode

This idea of keeping track of certain data might be extremely useful when we are doing expensive computations, we can store parts of the results in a cache and when we do a computation with a higher number, we can use the data from our cache as a base. This process is called memoization. A prime example of that would be working with factorials or Fibonacci sequences.


const factorialMemo = (function() {
  const cache = {}
  return function factorial(n) {
    if(n === 1 || n === 0) {
      return 1
    } else if (cache[n]) {
      return cache[n]
    } else {
      cache[n] = n * factorial(n-1)
      return cache[n]
    }
  }
})()


factorialMemo(5) //120
// cache object looks like {'2': 2, '3' : 6, '4' : 24, '5' : 120}
factorialMemo(6) // 6 * cached 120 

Enter fullscreen mode Exit fullscreen mode

Discussion (11)

pic
Editor guide
Collapse
kabircse profile image
Kabir Hossain

There is no double function. So how is it works ?

double(); //10
double(); //20

Collapse
danishsiraj profile image
Danish Siraj

The creator function is assigned to double here in this line

const double = creator(5)
double() //10

calling double is in essence calling the creator function.

Collapse
coderstoolbox profile image
Coder's Toolbox Author

Its calling what creator function returns not calling the creator ;)

Collapse
coderstoolbox profile image
Coder's Toolbox Author

There is, as the creator returns a function definition which you can call afterwards

Collapse
aybasaran10 profile image
Ahmet Yusuf Başaran

Check twice bro ur gonna figure it out!

Collapse
andrelomba86 profile image
andrelomba86

Nice post, but 0! = 1 or am I wrong?

Collapse
coderstoolbox profile image
Coder's Toolbox Author • Edited

What do you refer to?

EDIT: I can see it now, corrected, thanks

Collapse
jongmassey profile image
Jon Massey

Eh, in Javascript you can never be too sure ;)

Collapse
umutakyol profile image
asdsadasf

Forget it, if you need it, you learn it. It's not a big think, or hard to learn. But if youre goint to some interview, then learn it. Interviewers like this topic. :)

Collapse
asaduzzaman69 profile image
Asaduzzaman Himel

Everyone post tutorial in here! can I ask the question a post?

Collapse
shaijut profile image
Shaiju T

Yes you are welcome to ask questions related to this post. :)