Scopes in JavaScript!

Scopes in JavaScript!

Scope! is a crucial topic to get the hang of as a Programmer, it is a concepts in programming that applies to any programming language, and it also reveals the magic behind the scenes of how language Compilers and Engines carry out some of their duties, my Goal here is to explain in simple terms, whilst still revealing the technical parts you need to understand. Let's get to it! :)

Table of Content

  1. Overview of Scopes

  2. The Models of Scopes

  3. Lexical Scopes

  4. Conclusion

Overview of Scopes

In simple terms, scopes help the Compiler and Engine to identify where each variable/identifier was created in our program and retrieve their values when needed. yeah, that's it!

The word Identifiers are names you assign to elements in your program eg. (Variables, Arrays, Functions, etc.)

As simple as it sounds, scopes can also get complex, cause it works directly with the Compiler and the Engine, <- these guys need scopes to carry out their work.

// Global Scope
const name = "John Doe";

// Function Scope
function calculateAge(year){
    let currentYear = 2021;
    return currentYear - year;
}

// Block Scope
for(let i = 0; i < 5; i++){
    console.log(`Log ${i}`);
}

in the code above you'd find three types of scopes

  1. Global Scope (Notice the variable/identifier is not within any curly braces)

  2. Function Scope

  3. Block Scope

Here's a metaphor, think of an environment like your room, you'd surely find things in there; like a bed and probably a table right? but immediately you go outside you won't see what was in there anymore.

Because your brain has associated those things that make your room unique to that specific place in your house.

When our programs get executed the Compiler or Engine keeps record of every variable/identifier but associates them to an environment, either the Global, Function or Block environment so it can easily get their values when it wants them.

So think of Scopes as environments in our programs, let's take a look at each type of Scope.

Global Scope

the global scope is the most loosed environment, when identifiers can't be found in the other types of scope the compiler usually will end it's search in the global scope.

Function Scope

Function scope is just any environment that is a function, hence the name.

Block Scope

Any other environment that is not the Global Scope or Function Scope is going to be the block scope, usually would have curly braces.

Models of Scope

Scopes are classified, and it totally depends on the programming language you're coding in, but we're going to use JavaScript as an example, these classification is what is referred to as the Models of Scope.

  1. Lexical Scope

  2. Dynamic Scope

Lexical Scope

Lexical scope is the most common in programming languages, the term Lexical compliments the fact that JavaScript actually gets Compiled to some sort before the Engine executes the compiled result, I'm going to write on this whole fact soon, but for now, just know that the compilation happens so quickly, and the engine executes it immediately.

The First process it goes through while compiling is called Lexing/Tokenizing which is where we get the term "Lexical" from Lexical Scope.

Briefly, Lexing/Tokenizing is taking each expression in our program and then breaking them into a String of sequence (I will show you what that looks like) according to their meaning in any specific language in this case JavaScript.

// An Expression
let age = 10;

// Tokenzied 
"['{declaration: let}', 
'{identifier: age}', 
'{operator: =}', 
'{literal: 10}']";

This code above shows how an expression will mostly look when Tokenized.

So in simple terms a communication happens between the Compiler and the environment or Scope containing identifiers, this happens within that First process of compilation (Lexing/Tokenizing).

The idea behind Lexical scope is that the environment where the identifiers live is created when the function or block was originally written.

Look-Up

Another term we have to get used to is the word Look-Up.

When the compiler starts compiling our JavaScript code it needs to understand how each variable should be accessed so it doesn't get confused, so it depends on each environment to provide its identifiers.

function myFunc(){
    const paragraph = "I am a simple";

    function concat(){
        return `${paragraph} + paragraph.`
    }

    return concat();
}

myFunc();

When "myFunc" get's called in the code above, our Compiler first will identify the Scope of "myFunc" in this case it is the Global Scope, then it moves within the function and continues executing,

then it looks for the first variable/identifier it can find in the "myFunc" in this case it would be "concat" because of a concept called Hoisting in JavaScript (let's just continue though) and it's scope would be Function Scope.

When "concat" get's called it goes into the body of the function and repeats the step until it identifiers all the Variable/Identifiers scopes.

upon each look up if the compiler cannot get an identifier within an environment it goes up the parent of the environment to look up for that identifier if it still couldn't get it, it repeats the process until it gets to the global environment which is the end of the look up.

Conclusion

Scopes is a very significant for the compiler to identify where to get the right variable at the right time, the models of scope Lexical and Dynamic scopes tailored down to which programming language is being used.

For JavaScript it's Lexical and that proves the point of Tokenizing as the first step in Compilation of our program, since Lexical scopes depends on where a function or block is created, when an variable/identifier is not found it goes a step outside it's current environment to look for that identifier until it gets to the Global scope.

Hope this Explains it!

Thanks for Sticking around!

Israel juri.