DEV Community

Cover image for Scopes & Closures - A Metaphor
James F. Thomas
James F. Thomas

Posted on

Scopes & Closures - A Metaphor

Introduction

When I first began learning the ins and outs of basic coding, which I am still in the process of doing, the concept of “scopes & closures” was one that took me a minute to understand. I loved declaring variables, assigning values, and making things appear with console.log() statements. I truly felt like a wizard, creating my incantations, and watching them play out before my eyes. But once the tasks began to include loops and functions the concept of scopes appeared, and all the while threw me for a loop. So, I came up with a metaphor that helped me scope out the situation.

Scopes

What exactly is a scope?

alt text

More technical definitions of scope involve wording like, “the context of execution” (MDN) or “the level of accessibility” (W3Schools), but for me, the easiest way to explain scope to a newbie would be “the area of your code in which the variable or value was created”. I found this to be a simple and visually applicable definition that allowed me to start really grasping scopes and how they build upon or within one another. Being able to absorb the concept of scopes is the only way to move into closures, so let’s first expand a bit more on the types of scopes a newbie will need to comprehend.

Scopes come in two varieties:

alt text

The first and simplest to understand is the “global”. To the beginner “global scope” will encompass any variables or functions in your code that are not inside another function or conditional block. For my newbie’s let’s get visual, look at your code and if it’s not housed inside anything else, that would be the global scope.

// globally declared items 

let name = "James F. Thomas";

let age = 37;

let globalFunc = () =>{
  console.log("My First Blog Post")
}
Enter fullscreen mode Exit fullscreen mode

Yes, there are instances where an undeclared variable housed within a function will be automatically turned into a global variable, but that is beyond the basic overview of this blog. Remember we are keeping to the lowest level of abstraction for this one.

//undeclared variable in function

let globalExample = () =>{
  message = "My First Blog Post";
  console.log(message);
}
Enter fullscreen mode Exit fullscreen mode

The second scope type would be known as “local”. A “local scope” is generated when you initialize a variable or a function inside of another function, conditional statement, or loop code block. Placing the variable or value inside the curly braces of those previously listed code components will render them inaccessible or invisible to any components not in the same or local scope.

//local scoped variables

let outerFunc = () => {
  let localVariable = "I'm local"
}
Enter fullscreen mode Exit fullscreen mode

Locally scoped variables or values are considered children of the global scope in which they were created. It is with that relationship they will retain access to any globally located code components and be able to use them as desired. The technical term for this ability is “lexical scope”. This access continues with each nested function but is only one way in nature. So that means as we go from parent to child to grandchild each inner level can access outwardly but not vice versus. Kids access parent values, but not the other way around, and grandkids of course can take from both.

let name = "James F. Thomas";

let globalFunc = () =>{
  console.log(name)
}

globalFunc(); //prints "James F. Thomas"
Enter fullscreen mode Exit fullscreen mode

This child-parent interaction or “lexical” relation between local and parent code components is just what we needed to understand to find closure. Trust me that will be funny in a few lines.

Closures:

alt text

A “closure” describes the access a child element has to values housed in its parent or “lexical” environment. A closure is created when a function is housed within another and refers to its parent variables.

let outerFunc = () =>{

  let message = "I'm local"

  return function childFunc(){
    console.log(message);
  }; 

};

outerFunc()(); //prints "I'm local"
Enter fullscreen mode Exit fullscreen mode

Ok cool, so why is that important? Those variables and values not within the closure will only exist at runtime, so the closure or inner function will allow for future access even after the outer function has returned. So basically, a closure creates a type of barrier around the values it has accesses to and then allows you to store access to them even after the outer function has been run.

Conclusion:

Even though that all makes sense to me NOW, I had to come up with a more relatable explanation for these concepts during my first encounter with this topic.

So, in my head:

alt text

The global scope is an entire city, and any variable or function declared in it is a city service, and city services are available to all residents. Local scopes are gated communities within the city, with their own services, only available community to residents. Some subdivisions are huge and can have other smaller gated subdivisions inside of them, with their own services. Residents can of course leave their communities and access city services like the bus, but the bus does not run into any of these gated communities. For closures, I thought about the gated communities having their own service warehouses, that supplied goods and kept records, but the only way for non-residents to receive either was to make calls from the distribution center located in the city downtown. Lucky for us they are open 24 hours a day.

Yeah I know it’s silly but it worked for me, and maybe it will work for you.

alt text

Happy Coding!!!

alt text

Top comments (0)