We will be inspecting the following concepts and explain how the JavaScript engine is working in the browser:
– Execution Context
– Scope Chain and the Lexical Environment
The following index.html will be accompanying all app.js files used to demonstrate the above concepts.
//Index.html
<html>
<head>
</head>
<body>
<script src="app.js"></script>
</body>
</html>
Execution Contexts
//App.js
When I load the index.html file into the browser with the empty app.js file, I would expect to see nothing happening in the console or web page. We haven’t told JavaScript to do anything but does that mean that JavaScript has done nothing since there are no lines of code?
There is in fact one object available to us in the console, the window object!

We also have this same window object assigned to this

Both of these objects were given to us because JavaScript has built a Global Execution Context for us.

In JavaScript, an Execution Context is the environment that JavaScript code runs in. The Global Execution Context is the base Execution Context. The Global Execution Context creates two things for you, a ‘Global Object’ and ‘this‘. As we saw earlier, in the browser window object is the Global Object and it is assigned to this at the global level. Other things in the Execution Context are the Outer Environment and Your Code. In a Global Execution Context the Outer Environment is null. In this case, since we have nothing in our app.js file, we have nothing in the Execution Context for Your Code.
Further Breaking Down the Execution Context
Covered concepts:
– Hoisting
– Execution Context Creation
– Execution Context Stack
– Function Invocation
– Single Threaded
– Synchronous
//app.js
console.log(var1);
fun1();
var var1 = "var1";
function fun1() {
console.log("fun1")
}
fun1();
console.log(var1);
What would you expect the console output of the following code to be? When I first looked at this code, I thought that either the JavaScript engine would throw an error or the variable and function instantiation would not matter and it would print this sequence, “var1” “fun1” “fun1” “var1”. Instead, this was the console output!

The first console log of var1 was undefined yet the first invocation of fun1 printed “fun1”. This is because of a concept called hoisting. The Execution Context has two phases, inside of the first phase, Creation Phase, the JavaScript engine sets up memory space for functions and variables The difference here between the variable and function is that the engine will put the entire function into the value of the memory key whereas the variable is initialized with undefined, a special keyword in JavaScript.
The second phase, the Execution phase is where code is being run line by line inside of the Execution Context environment. Anytime we have function invocation, a new Execution Context is created and put onto the Execution stack. This is visualized below using the following app.js file.
//app.js
function fun1() {
// Do nothing
}
function fun2() {
fun1()
}
fun2()
Here when the program is starting, a Global Execution Context is created. fun1 and fun2 are assigned places in memory, the global object is created and this is assigned to it during the Creation Phase.

During the execution phase, the JavaScript engine makes it’s way to the invocation of fun2 and immediately creates an Execution Context for fun2 adding on top of the Execution Stack. Inside of the Execution Phase of fun2’s Execution Context, fun1 is invoked creating another execution context to add to the Execution Stack. Once all code in fun1 is resolved we will pop off the fun1 execution context, then fun2 execution context once it’s resolved and then the Global Execution Context. Now the JavaScript Engine has nothing more to do.
JavaScript is single-threaded and synchronous meaning the above code was executed one line at a time in a single execution context at a time.
Scope Chain and the Lexical Environment
//app.js
function fun1() {
console.log(myVar, "fun1")
}
function fun2() {
var myVar = 4;
console.log(myVar, "fun2");
fun1()
}
var myVar = 2;
console.log(myVar, "Global Scope");
fun2();
Above, we have three console log statements. Our output is shown below:

Does this output surprise you? Where JavaScript code physically exists is important. This is what the Lexical Environment is, where your code is physically defined. The Lexical Environment determines what the outer environment is for the Execution Context. This is then a crucial piece in the Scope Chain. Here, fun1 was defined in the Global environment. The fun1 Execution Context has to look to its outer environment to find the myVar variable. Because it was defined in the Global Environment, it will look in the Global Environment next. It doesn’t matter that fun1 was invoked inside of fun2, just where it was defined. If fun1 was defined and invoked inside of fun2, it would have console logged a value of 4 and “fun1.”

The Scope Chain will not stop linking to the next Execution Context down until the outer environment is null which is the Global Execution Context.
Wrapping Up
I hope you have a better understanding of what’s happening, under the hood, in JavaScript. Please leave comments if I’ve gotten anything wrong or you have any inquiries!