cover-img

JavaScript Function Scope

20 January, 2023

7

7

2

Introduction

This series is all about visiting JavaScript fundamental concepts with more significant details. In this show, we will learn another important concept called Scope. We will also learn and appreciate the importance of the Scope Chain.

Quiz Time

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?

Scope

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.


Recap

Here are some of the key points from our Understanding of JavaScript Execution Context:

  • There is something called Global Execution Context and Function Execution Context.
  • Each execution context has a special thing called this and the reference to the Outer Environment.
  • When we invoke a function, the JavaScript engine creates an outer reference for the current Function Execution Context.
  • The function has access to the variables defined in the Outer reference. The JavaScript engine does a look-up when it is unable to find it in the current execution context.

Scope and Scope Chain

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.

functions.png

  • The variable name was created in the global execution context and assigned a value as cartoon in the execution phase.var name = 'cartoon';
  • When the function tom() was invoked, the JavaScript engine created an execution context for tom() and a reference to the outer environment, the global execution context.tom();
  • When tom() invokes 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,

flow_1.gif

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.

scope_chain.png

Change in the 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!

flow_2.gif

Block Scope

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";
console.log(name);
}

console.log(name);

Had we created the variable name with var instead of let, we wouldn't have found this block scope restriction. Here is another example,

{
let name= "tom"; console.log(name);
}
{
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++) {
console.log(counter);
}

console.log(counter);

Conclusion

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.



7

7

2

ShowwcaseHQ

San Francisco, CA, USA

Showwcase is where developers hang out and find new opportunities together as a community
Tapas Adhikary
Educator @tapaScript | Teaching JavaScript/React/FullStack | Writer | YouTuber | Founder reactplay.io

More Articles