JavaScript Scope Fundamentals with Tom and Jerry

Co-Founder, @CreoWis | Teacher, @tapaScript | Founder, @ReactPlay | YouTuber | Writer | Human
Search for a command to run...

Co-Founder, @CreoWis | Teacher, @tapaScript | Founder, @ReactPlay | YouTuber | Writer | Human
I love reading your entire Cracking the Nuts series! It's always so insightful and well-explained! Thanks!
In this series, I'll bring some fundamental concepts from JavaScript to you. It is going to be fun learning for JS Beginners(and for Experienced folks too) to get the foundation right.
Joy of getting to the end All's well that ends well. Welcome to the last post of the series JavaScript: Cracking the Nuts. I want to thank you all for liking the series so far. There is another reason why this article is special to me. This is my 5...
Traditional SSR is great, but it has a massive buffering problem. Let's look into the SSR Streaming and learn how it could be a game changer.

Learn how to build maintainable, reusable forms in React using design patterns like custom hooks, compound components, and context for scalable CRUD

Learn how JavaScript variables work, including let vs const, primitive and reference types, pass by value, and how JavaScript stores data in memory.

A beginner-friendly introduction to JavaScript covering what it is, how it works, and how to set up your JavaScript environment

Learn how the promises are handled internally using event loop. This concept is essentials to debug and work with async programming.

GreenRoots Blog - A Blog by Tapas Adhikary
186 posts
Educator | YouTuber | Building ReactPlay | Let's Connect
Welcome to another post of the series, JavaScript: Cracking the Nuts. This series is all about visiting JavaScript fundamental concepts with more significant details. In this article, I am going to explain another important concept called Scope. We will also learn and appreciate the importance of the Scope Chain.
If you are new to the series and want to check out the previous articles, here are the links,
Thank you for showing all the love to the series so far, I really appreciate your feedback, likes, and constructive criticisms. I hope you find this one useful as well.
What will be the output of the following code execution and why?
function jerry() {
console.log(name);
}
function tom() {
var name = 'tom';
jerry();
}
var name = 'cartoon';
tom();
Is it going to be cartoon, tom or undefined? But more importantly, how are you deciding on an answer here? Are you going by the Scope? What about the execution context?
The answer to the question I have asked above is, cartoon. Let us explore and understand it further.
In JavaScript, Scope is the mechanism to determine where the variables exist to use. The variable may exist inside or outside of a function call.
Let us break the above code into pieces and see how the variable's accessibility changes depending on where the variable has been declared, and the functions are created.
Here are some of the key points from our Understanding of JavaScript Execution Context:
Outer Environment.In the example above, there are two function invocations, tom() and jerry(). Hence there will be two different function execution contexts created.
Remember, there is always a global execution context created where the keyword this is equal to the Window object. Hence we have a total of three execution contexts here, one Global Execution Context and two function Execution Contexts of tom() and jerry() respectively.

name was created in the global execution context and assigned a value as cartoon in the execution phase.var name = 'cartoon';
tom() was invoked, the JavaScript engine created an execution context for tom() and a reference to the outer environment, the global execution context.tom();
jerry(), JavaScript engine identifies the lexical position of jerry() and does the same. It creates an execution context of jerry() and a reference to the outer environment.function tom() {
var name = 'tom';
jerry();
}
Hold on. What's the outer environment of jerry()? Is it the execution context of tom() or the global execution context? This depends on the answer to another question.
Who created
jerry()? Where is it sitting lexically?
jerry() is created by the global execution context even though it was invoked in tom()'s execution context. We find that jerry() sitting lexically at the global execution context and created by it. As we go by this theory, jerry() is having a pointer to the global execution context.
So far, so good? We also find, jerry() doesn't have a variable declared called name in it. In the execution phase, it tries to log the name variable.
function jerry() {
console.log(name);
}
In the execution phase, the JavaScript engine starts the look-up process following the outer reference of jerry() and finds a variable name created with value, cartoon in the global execution context.
Now we know why the answer to the question has to be cartoon, not tom or undefined. Here is the visual flow of how the scoping took place,

The whole process of looking up for the variable in the current execution context and outer references form a chain called the Scope Chain. We can also conclude that the variable name is in the scope of the function jerry() because it was successfully found in its scope chain.

Quiz time again! What will be the output of this code execution?
function tom() {
var name = 'tom';
function jerry() {
console.log(name);
}
jerry();
}
var name = 'cartoon';
tom();
We have made a small change in the above code. Now the function jerry() is created inside tom(). The reference to the outer environment from jerry()'s execution context will be pointing to tom()'s execution context. Hence the variable name will be found in the scope chain as defined in the tom() function. So you know the answer is, tom!

As we got the fundamentals of scope, let us understand what block scope is. A code block is defined by these braces {...}. If a variable is declared within a code block using a keyword called let, it’s only visible inside that block.
{
let name = "tom"; // only visible in this block
console.log(name); // tom
}
console.log(name); // Error: name is not defined
Had we created the variable name with var instead of let, we wouldn't have found this block scope restriction. Here is another example,
{
// declare name
let name= "tom";
console.log(name);
}
{
// declare name in another block
let name = "jerry";
console.log(name);
}
This is going to work perfectly fine and logs tom and jerry in the console.
Even for if, for, while etc, variables declared inside the block({...}) are only visible inside it. Here is an example with for loop,
for (let counter = 0; counter < 10; counter++) {
// the variable counter is with let
// hence visible only inside the block {...}
console.log(counter);
}
console.log(counter); // Error, counter is not defined
Understanding scope with the fundamental concepts like execution context, outer reference, lexical positioning, etc., will help debug the tricky bugs(those horrible production ones) with ease. We, as JavaScript developers, will be more confident about how things work internally.
Here are a few references I liked and followed on this subject,
I hope you find the article useful. Please Like/Share so that it reaches others as well. If you enjoyed this article or found it helpful, let's connect. You can find me on Twitter(@tapasadhikary) sharing thoughts, tips, and code practices.
To get e-mail notifications on my latest posts, please subscribe to my blog by hitting the Subscribe button at the top of the page.
Up next in the last post of the series, I'll be explaining another fundamental concept called, Closure. Stay Tuned.