Scope and Closure in Javascript
…and how to solve “Calculating With Functions” on Codewars
Ahhh, scope and closures: 2 favorite tech interview questions that trip up devs of all ages!
Let’s talk scope. What is it?
Scope is access. That’s the easiest way to think about it. It allows you, as a developer, to limit access to certain variables to specific contexts. It has two benefits:
- security — variables that are not accessible from outside the specified scope won’t accidentally get changed later on
- naming — allows you to use the same variable name in different scopes (you know this is helpful if you’ve used
let i = 0
in separatefor
loops in the same function 🙋♀️)
Scope is often discussed in the context of functions, but I found it helpful to first think about it in the context of a nested object (functions are JS objects anyway…)
Here’s an example of an object with several layers:

Here we have the wildly under-appreciated Baked Alaska, and it has several layers. If I wanted to know what ice cream is under the meringue, I couldn’t just write bakedAlaska.iceCream
— I would get undefined
. I would have to write bakedAlaska.innerLayer.iceCream
to get to the array of ice creams. That’s because curly braces make their own scope. So the iceCream
array is not defined in the direct scope of bakedAlaska
. It’s defined inside the scope of innerLayer
.
Types of Scope
Global Scope — this is outside of any functions or curly braces. If a variable is defined in the global scope, it can then be used anywhere in your code (including functions, objects, etc.) It’s not encouraged to declare variables in the global scope because of the reasons listed above.
Local Scope — when variables are only accessible within a specific context (like a function, or in curly braces)
- Function Scope — a type of local scope. Variables declared inside of a function cannot be accessed outside of that function.
function sayMyName(){
let myName = "Julia"
console.log(myName) // "Julia"
}console.log(myName) // undefined
- Block Scope — a type of local scope, and a subset of function scope. Variables declared inside of curly braces are not accessible outside of those braces (just like in the function above.)
You promised to talk about closure…
So I did. Here’s MDN’s definition, and then we’ll unpack it:
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
“In other words, a closure gives you access to an outer function’s scope from an inner function.” Let’s see this in action using a similar example to the one above:

As you can hopefully see, even though the outer function was invoked on line 14 and has essentially “come and gone,” the inner greet
function still has access to the variable myName
whenever it is later invoked. Let’s put this to work on a less contrived example.
Solving the “Calculating With Functions” problem using closure
I came across this question only a month or two into my journey as a programmer. My brain melted while trying to come up with a solution, and the question sat marinating in the back of my head for months. Recently, after re-visiting the subject of closure, I realized that was the piece I was missing.
The instructions are to create functions that when called in the example way below, will return the correct answer.
e.g. seven(plus(five())); // must return 12
four(times(nine())); // must return 36
Here are some additional stipulations:
- There must be a function for each number from 0 (“zero”) to 9 (“nine”)
- There must be a function for each of the following mathematical operations: plus, minus, times, dividedBy (
divided_by
in Ruby and Python) - Each calculation consist of exactly one operation and two numbers
- The most outer function represents the left operand, the most inner function represents the right operand
- Division should be integer division. For example, this should return
2
, not2.666666...
:
My first thought was that I’d have to work from inside out, since each function would have to wait for its received function to resolve before completing execution. (See my post on call stacks if that doesn’t make sense!)
With that in mind, I started by thinking about the number functions. My thought was that the number function could either be on the outside, taking in an operator function as an argument like this: seven(some operator function here)
, OR it could be on the inside, receiving nothing, but returning a number: the five()
of seven(times(five()))
. So that’s exactly what I did:

Each number function must be able to accept a function as an argument, since an operator function might be called inside, like in the example: seven(plus(five()))
. If you’re familiar with ternary expressions, you could also write the function out like this:
function seven(fn) {return fn ? fn(7) : 7}
I used similar logic for the operations functions. They would need to be able to accept just one number function as an argument plus(five())
. The part where I was getting stumped previously was how those operations functions would get access to both the outer number and the inner number.
Here’s where the beauty of closures comes in.

I’m going to repeat the logic that’s written in the comments of the snippet above.
- The first thing we do is accept an argument (x). In this example, that’s the return value of
five()
, i.e. 5. - Then we define an inner function that utilizes the value of x inside of it and accepts an argument of a number. Because the inner function has access to the outer function’s scope at the time of its definition, it will be able to use the value of x even after the outer function is long gone. Closure coming in clutch.
- Then the outer function returns a reference to the inner function.
So now that we have all the pieces to the seven(plus(five()))
expression, let’s walk through each step, replacing each function with the return values as they get resolved.
seven(plus(five()))
gets called.- The innermost function,
five()
gets evaluated first. Based on our conditional statement from before, we see that this will just return the number 5. - Now we move out to
plus(5)
. Based on our code snippet, we see that x is assigned the value of 5 that our inner functionadd
will have access to, and return a reference to theadd
function. - Then we move out to
seven(add)
. Based on the same function as before, we see that this time a function was, indeed passed in. Therefore, the return value is the functionadd
invoked, with the number 7 passed in. - Finally,
add
executes using the remembered value of 5 from its outer scope, and the passed in value of 7, for a return value of 12. 🤯
One of my instructors mentioned that a good way to picture closure was to imagine that your inner function has access to some variables “inside a backpack,” which I thought was a really charming and helpful way to think about it. So we’ll close out with this (hopefully memorable) meme.