DEV Community

James Sinkler
James Sinkler

Posted on • Edited on

Closure

Cat in a box
Very adorable cat in a box

Photo by Luku Muffin on Unsplash

Javascript Closure

Ok so what's with the cat in the box?

Well in my mind the cat represents the variables you get access to each time you use a function that was returned by another function. In general you are grabbing the box (the function) to use as a box. But you get access to a cat (variable tied to the scope) each time as well, even though it's not really a part of the box. Hopefully by the end of this that will make sense.

We will look at how this would work in a little function to update the score in a game.

You might think, ok, I could have a global variable called score, and then inside of it just update that score each time a player gets a point.

let score = 0;

const playerScores = ()=> {
  score++
  return score
}
Enter fullscreen mode Exit fullscreen mode

This would work fine, and I've definitely written functions that mutate something not directly defined inside of it. Functional programming people would take issue with this function on the following basis. Not that we care about following strictly functional programming right now.

  • It returns a different value every time you call it
  • It accesses variables defined outside it
  • It updates a value and mutates it to be another value

Mutated Apple
Mutated Apple

Photo by Diana Polekhina on Unsplash

We aren't really going to write this in the functional paradigm but we will address one of these points. The main bullet from above that we are going to deal with is:

  • It accesses variables defined outside it

Ok. Back to the cat in the box. score is the cat in this case. We want to make it a part of the function. It will help us keep track of this variable since it is tied to this function.


const playerScores = ()=> {
  let score = 0;
  score++
  return score
}
Enter fullscreen mode Exit fullscreen mode

How about this? Problem solved right?

  • we call playerScores()
  • score is initialized at 0
  • score is updated by 1
  • score returns 1

(The issue of course is when we call it again the same thing happens and it always returns 1)

I'm imagining maybe I have multiple levels to this game, and when we get to a new level, the score goes back to 0. So there is some value in that let score = 0 declaration. But at the same time, it won't be a fun game if we can only get to score 1.

Enter the closure. This will give us a way to track score and update it for different levels. If we go ahead and declare score like we did, but then return a new function that updates score we get access to it.


const playerScores = ()=> {
  let score = 0;
  return updateScore() {
    score++
    return score
  }
}
Enter fullscreen mode Exit fullscreen mode

Now when we call playerScores() we don't update the score, we get the inner function updateScore returned, but it has access to that score initialized in the parent. It get's access to the cat in the box.

// save the returned function to a variable
const roundOnePlayerScoresAPoint = playerScores()

// call that returned function
roundOnePlayerScoresAPoint()

// call it again
roundOnePlayerScoresAPoint()

// call it three times
let thirdReturn = roundOnePlayerScoresAPoint()
console.log(thirdReturn) // what's the score?
Enter fullscreen mode Exit fullscreen mode

It was the same cat in the box each time you called it. It was the same score that was originally initialized when we created roundOnePlayerScoresAPoint. Our returned function had it in it's closure. It looks back at the function that defined it, and when it is asked to update score, score++, it says hmm there's no score defined in myself, was there one back in that box? Yes! So it goes ahead and updates the one defined above it in the parent scope.

What I find nice about this, is now if we want our player to go to level2 and restart the score, I can just call a new instance of playerScores.

const roundTwoPlayerScoresAPoint = playerScores()

roundTwoPlayerScoresAPoint() // this will only update the new score that was just initialized

// score = 1 in round two now,
// score = 3 in round one still,
Enter fullscreen mode Exit fullscreen mode

So when you call that parent function again for a new instance of the returned function. You get a new score initialized. It's like getting a whole new box, with a different kitten inside.

Hope you found that enjoyable, maybe you will find a usecase for this somewhere soon.

Happy Coding,

James

Top comments (0)