How to Nail a Scope or Closure Question on Your Next Dev Interview

Practicing your interview skills for that new job? This quick run-down of scope and closure will help you ace these JavaScript basics.

Written by Julia Zolotarev
Published on Jun. 13, 2022
Brand Studio Logo

Ahhh, scope and closure: two favorite tech interview questions that trip up devs of all ages! Let’s get right to the good stuff (it’s ice cream). 

What Are Scope and Closure in JavaScript?

Scope is access; that’s the easiest way to think about it. Scope allows you, as a developer, to limit access to certain variables to specific areas. 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.

 

What Is Scope?

Scope is access; that’s the easiest way to think about it. Scope allows you, as a developer, to limit access to certain variables to specific areas.

Scope has two benefits:

  • Security :  Variables that aren’t 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 separate for loops in the same function (ahem…)

We often discuss scope in the context of functions, but I found it helpful to first think about scope in the context of a nested object (functions are JS objects anyway…).

Here’s an example of an object with several layers:

what-is-scope-closure-javascript
Is anyone surprised I’m using a food example? Didn’t think so.

Here we have the wildly under-appreciated baked Alaska, which has several layers. If I wanted to know what ice cream is under the meringue, I couldn’t just write bakedAlaska.iceCream  because  I would get undefined. I would have to write bakedAlaska.innerLayer.iceCream to get to the array of ice creams beneath the meringue. 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.

JavaScript Tutorial | Scope and Closure

 

Types of Scope

What Is 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.) Declaring variables in the global scope isn’t considered a best practice because of the reasons listed above.

 

What Is Local Scope? 

When variables are only accessible within a specific context (like a function, or in curly braces), you’ve got a local scope.

More From Julia ZolotarevCreate React App and TypeScript — A Quick How-To

 

What Is Function Scope?

Function scope is a type of local scope. Variables declared inside a function cannot be accessed outside of that function.

function sayMyName(){
  let myName = "Julia"
  console.log(myName) // "Julia"
}
console.log(myName) // undefined

 

What Is Block Scope? 

Block scope is another 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).

More From Our Software Engineering ExpertsWhat Is the @ Symbol in Python and How Do I Use It?

 

What Is Closure?

Here’s MDN’s definition: “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.”

Let’s unpack that.

“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:

what-is-scope-closure-javascript

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’s invoked later. Let’s put this to work on a less contrived example.

More Career Advice From Our ExpertsSo You Want to Be a Full Stack Developer? Here Are the Skills You Need.

 

Solving “Calculating With Functions” 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. After re-visiting the subject of closure recently, I realized that was the piece I was missing.

 The instructions are to create functions that, when called in the example below, will return the correct answer. For example: 

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 consists 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, not 2.666666

My first thought was that I’d have to work from the 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:

what-is-scope-closure-javascript

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()). Here’s what stumped me: How were those operations functions getting access to both the outer number and the inner number?

Here’s where the beauty of closures comes in.

what-is-scope-closure-javascript

 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, the inner function 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.

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.

  1. First, seven(plus(five())) gets called.
  2. The innermost function, five() gets evaluated first. Based on our conditional statement from before, we see that this will just return the number 5.
  3. 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 add function will have access to, and return a reference to the add function.
  4.  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 function add invoked, with the number 7 passed in. 
  5. 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 once told me 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.         

Explore Job Matches.