Yeh lexical scope hai kya?

Jainishshah
5 min readFeb 5, 2021

Hola Developer!!!! Well I know that is a bit dramatic title, but that truly describes my feeling when I read this term again and again be it understanding how “this” works in JS or what is a closure or solving console questions. Lexical scope is one of the fundamental concepts in JavaScript, so let me demystify this cool thing.

Every program, written in any language has only one job => perform computation. Now to run some specific business logic the program might need to store some variables and access them later this is what gives your program a state and variables are key to do that. But can we just use any variable anywhere? No, right. Well, there are some rules regarding what variables the current running piece of code can access. These sets of rules are called Scope.

In JavaScript, you have the functional scope, block scope, and global scope, but what do they even mean? To understand this we will have to drill down a little into how JS works under the hood, let me introduce to you the “Engine”. There is a common misconception that JS is an interpreted language. Well, it’s not (until someone develops an engine that doesn’t do optimizations). Your JS code will be compiled few microseconds or even smaller time frames before your code executes. But why do we need to compile JS even? Well the JS engine uses all kinds of tricks to optimize your code for faster execution. A certain example can be that even before executing the code the engine will know what identifiers(variables/function) will be present in the code so that during execution it is faster to retrieve.

At this point, you might be thinking what am I blabbering about, what relation does it have with scope. Well don't be mad, I promise by the end of the blog you’ll find it useful.

So where were we… oh ok the engine. Yaa so let’s take a piece of code and understand the compilation phase and execution phase and creating of Scope.

var c = 5function doSomething(a){    function printIt(b){
console.log(a + b + c);
}
printIt(3);}doSomething(2);

A simple piece of code right. But here’s a question how does the function printIt() even know the value of “c” or “a” or “b”.

Let’s drill down. When the compiler encounters this piece of code it will parse it

  1. There is a method called doSomething, the compiler will see this as a function declaration and will store this definition in heap and without going into this function it will move on
  2. The compiler will see there is a call to this function and the code ends so this piece of code will go to the “engine” for execution
  3. the engine will ask the compiler where the definition of fn() is and then execute with parameter 2.
  4. Again the compiler will come into the picture as a new fn is encountered. This is basically called function scope( Each time a new function is encountered a separate scope is created). All variables and fn declarations will be available to this fn only and its instances (if any) and not anything outside this.
  5. The compiler will then parse through the doSomething fn. It will ask scope to declare a variable “a” and then assign to it the value 2.
  6. This is what the scope will look like now
Scope : [(of DoSomething) => { a: 2} ]->[global => {c : 5}]

7. Again this parsing will go on, the definition of printIt will be stored and the engine will execute the printIt() with parameter 3.

8. This is what scope will look now

Scope : [ (of printIt) => {b : 3}]->[(of DoSomething) => { a: 2} ]->[(global) => {c : 5}]

9. Now when the engine will execute the printIt function it encounters console.log()

10. The engine will first ask where the console is and then find the log fn. When the log fn asks for values of “a”, “b”, “c”, engine will ask Scope for its values. The scope will find “b” in the current scope and return its value, it doesn’t find “a” in the current scope and will move up the chain to find the value of “a” (in the doSomething scope). Again for the value of c, it will move up the chain to find “c” in the global scope.

11. Once all the values are retrieved you get the result “10” printed on the console.

Well, this is what lexical scope is.

We learned 2 things function scope and global scope. But what is block scope now?

'use strict'
function abc() {
var a = true;
if(a){
var z = 5;
} else {
var z = 6;
}
console.log("z = ", z);
}
abc();

Take the above function for example, what do you think the console.log() would print? And what should logically it print?

Well, ideally it should print “undefined” in non-strict mode. Since the variable z is declared in the if-else clause block it shouldn’t be accessible outside it. The engine will make the Scope check for the value of “z”.

Scope : [ (abc) => { a : true}]->[ (global) => {}]

As usual, the scope will move up the chain till the global scope and will find no variable called z. In “non-strict” mode it will print “undefined” and in “strict” mode will throw “Reference Error”. ( Discussion of ‘strict’ vs ‘non-strict’ is beyond the scope of discussion for this read)

But sadly, the result of console.log() will be “z = 5”. But why ??

Well, the reason is JavaScript is built in this fashion, everything is functional scope. So even if you have something declared in if-else or for/while/do-while loops clause or in any block, that variable is populated in the scope of that function. So the scope will look something like this after the engine has executed the code.

Scope => [(abc) => {a: true, z: 5}]->[(global) => {}]

To solve this problem two new keywords “let” and “const” were introduced in the ES6 (ES2015) version of JS.

function abc() {
var a = true;
if(a){
let z = 5;
} else {
let z = 6;
}
console.log("z = ", z);
}
abc();

Now using the “let” keyword you’ll get “Reference Error” when the engine executes console.log(z);

And the scope will look like this.

Scope => [(abc) => {a: true}]->[(global) => {}]

So this is the end of this article, It was a long read but I hope you learned something today or had your concepts refreshed. In case of any discrepancy do reach out. For any further communication, you can reach out to me at jainishshah12@gmail.com.

--

--