DEV Community

Cover image for Mastering JavaScript 🧑‍💻: Closures
Saverio683
Saverio683

Posted on

Mastering JavaScript 🧑‍💻: Closures

Hello everyone 👋, I hope you are doing well.

In this post I will explain what closures are using examples as well so that you too can use them to write your code better.

LEXICAL SCOPE ✍️

Before directly explaining what closures are, it is appropriate to explain the concept of scope and lexical scope.

The scope of a function refers that area of code where its variables are "visible" and can be used.
If another function is created within one function, another internal scope will then be created, and so on: this is called a scope chain.

Lexical scope, also called static scope, refers to when the location of a function's definition determines which variables you have access to.

E.g. :

const life = () => {
  const pastEvents = 'past'

  //console.log(actualEvents) this will create an error because that inner variable is not accesible here

  const present = () => {    
    const actualEvents = 'present'

    console.log(pastEvents, actualEvents)//ok
    //console.log(futureEvents) same for this one

    const future = () => {
      const futureEvents = 'future'

      console.log(pastEvents, actualEvents, futureEvents)//ok      
    }

    future()
  }

  present()
}

life()
/*
Outputs:
  past present
  past present future
*/
Enter fullscreen mode Exit fullscreen mode

As you can see, in a nested group of functions the inner functions have access to the variables and other resources of their parent scope.

CLOSURES 🪆

Let's make some changes to the code from before:

const life = () => {
  const pastEvents = 'past'

  const present = () => {    
    const actualEvents = 'present'

    console.log(pastEvents, actualEvents)

    const future = () => {
      const futureEvents = 'future'

      console.log(pastEvents, actualEvents, futureEvents)  
    }

    return future
  }

  return present
}

const newFunc = () => {
  //different scope
  const newLife = life()
  const future = newLife()

  future() 
}

newFunc()
/*
Outputs:
  past present
  past present future
*/
Enter fullscreen mode Exit fullscreen mode

New functions created within the newFunc function have access to the variables pastEvents, actualEvents and futureEvents even if they are in another scope.
This is because the future and present functions are closures: when they are assigned to variables (in our case newLife and future) they close over (from here the term closure) the variables of their lexical scope.

Due to this the closures are memory efficient saving code repetitions.
Here another example:

const addTo = x => y => x + y //x = outer func; y = inner.
const addToTen = addTo(10)
addToTen(3) // returns 13
Enter fullscreen mode Exit fullscreen mode

Another benefit they bring is that of data encapsulation:

const createCounter = () => {
  let count = 0

  return {
    increment() {
      count++
    },
    decrement() {
      count--
    },
    showCount() {
      console.log(count)
    }
  }
}

const myCounter = createCounter()

for(let i = 0; i < 100; i++)
  myCounter.increment()

myCounter.decrement()

console.log(myCounter.count)//returns undefined
myCounter.showCount()//returns 99
Enter fullscreen mode Exit fullscreen mode

In this way, the count variable is private and can be accessed only through proper functions written by the developer.

CONCLUSIONS

If you have come this far in reading, I thank you. If you liked the post please leave a like and check out my other posts 🙂.

Top comments (0)