JavaScript compiler , Scope & TDZ in depth
Published: 2020-05-15 07:28:15

**JavaScript is a compiled & interpreted language** 


Most of the beginners  can confuse about this statement. When we are coming from C, C++ background, where the those compilers can compile our code into low level, the *JavaScript compiler* is different than that.


To understand the role of compiler in JavaScript,We should know about roles of *JavaScript Engine*.


![Alt text of image](https://dev-to-uploads.s3.amazonaws.com/i/499h8jaso7eyevst91ad.jpg)


Now let us understand the role of compiler with an example.

**var data=100;**


It is variable declaration and initialization.Even though it is appearing as single statement,Actually, 
" **It is combination of two different actions which can occur at two different situations** " 

**Action-1**: 
* when compiler encountering "var a", then ,it asks scope,to see a variable "a" already existed for that particular __scope collection__ .
* If it is already there,the compiler ignores the declaration and moves on.
In this example, the variable is global and not already existed, so the compiler asks __Scope__ to declare a variable in its __Scope collection__

* Compiler then produces code for Engine to later execute, to handle the a = 2 assignment. That means __assignment(data=100)__ will be done during execution

So, the scope of a variable is decided during __compilation time__ and assignment will be done during __execution time__


{% runkit

%}
var data=100;
return data;
{% endrunkit %}


The same thing will be happened to a function also. That means the function declaration will be done at a specific scope during compilation and assignment of function definition will be done during execution.

{% runkit

%}
var testFunction=function(){
       return "testFunction called";
}

testFunction();
{% endrunkit %}


Note: _The JS engine compiles your code sometimes during execution,especially when dealing with function execution_


With this knowledge,let us try the following example.

{% runkit

%}
return a;
var a=100;
{% endrunkit %}

Here, actually, we expected an error, because we returned the value of variable "a" before it is even declared. But surprisingly, it returned "undefined" which is _default value_ of a variable.This is because, the __scope__ of variable a is declared during compilation and also initialized with "undefined". That why,it has returned "undefined" instead of error. That means, the variable declaration is "  _Hoisted_  ".

Now let us observe the following
{% runkit
%}
return a;
{% endrunkit %}

It has generated "Reference Error" ,because __RHS lookup__ failure.It means,it search for the value of a variable which is not yet declared. So, that variable declaration is not available at its _Scope_ .

The same thing would be happened with functions too.
{% runkit

%}
//calling function before declaration
//but the declaration will be hoisted
testFunction();
 function testFunction(){
      console.log("test function called");
}
{% endrunkit %}

But when we assign a function to a variable, the that variable will be hoisted and generates _Type error_

{% runkit

%}
//calling function before declaration
//but the declaration will be hoisted
testFunction();
 var testFunction=function (){
      console.log("test function called");
}
{% endrunkit %}






**Temporal Dead Zone**
----------------------

Here is the MDN’s explanation of the temporal dead zone:
*In ECMAScript 2015, let bindings are not subject to Variable Hoisting, which means that let declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a ReferenceError (contrary to a variable declared with var, which will just have the undefined value). The variable is in a “temporal dead zone” from the start of the block until the initialization is processed*

To understand this lengthy statement, first we should know the difference between the old one ,called "var" and the "let" which was introduced in __ES6__.

Variables declared by "var" has _Function scope_ and those declared with "let" has _Block scope_

{% runkit

%}
var marks=90;
var testFunction=function(){
       if(marks>80){
       let status="First grade"
       return status;
       }
}

testFunction();
{% endrunkit %}

Here the variable "marks" is in _global scope_ which can be known to all functions of that file. But the variable "status" has _Block scope_ and known only to _if block_ . When we tried to access "status" from outside of _if block_, it generates _Refference error_


{% runkit

%}
var marks=90;
var testFunction=function(){
       if(marks>80){
       let status="First grade"
      
       }
 return status;
}

testFunction();
{% endrunkit %}


Now, let us see about TDZ of "let". Once we revisit the the definition of TDZ,"let bindings are not subject to Variable Hoisting". That means like "var", the variables declared with "let" will not be hoisted. That means no initialization will be done automatically like "var" with "undefined".
 
{% runkit

%}
let a=100;
return a;
{% endrunkit %}

But, because of TDZ, the variables declared with "let" will not be initialized. Because of this fact, when we try to access then before their initialization we will get _Reference error_
{% runkit

%}
return a;
let a=100;

{% endrunkit %}



Hope this brief discussion helped you to understand the basics in clear way.