Javascript is Fun! 🖤 - Part 1

Javascript is an infamously difficult language to predict. Understanding one of the most fundamental parts of Javascript, the Execution Context, will give you a better understanding of why Javascript behaves how it does.

The execution context is the environment in which Javascript code is executed and it is created in two phases: the creation phase and the execution phase. It is a wrapper that takes your code and “wraps” it in a context.

Creation Phase

The first phase in this stage is called the creation phase. In this phase, we have the base global execution context, which creates the global object and the special variable this.

Global object

Global refers to code and variables that aren’t inside a function. Usually, in this context, it will be the browser’s windowobject. For example, if we run the following:

var a;function b() {}

Upon inspecting the window object, we see both the variable and the function as part of the properties of the object. We can also access them by calling them directly on the window object:

> window.a< undefined // more on this in a moment> window.b< ƒ b() {}

Note: If you are running Node.js or running Javascript on the server, the global object will be something else, but there will still be a global object.

this

The other object created is this. In the global execution context, this refers to the global object (whether you are in strict mode or not).

Aside from the global object and this, there's also a link to the outer environment. When you're running code inside a function, that means running the code outside the function. But when you're running at the global function, there is no outer environment and it becomes null at the global level.

hoisting

Let’s talk a little bit about what Javascript does to create an execution context and the weirdness that hoisting may bring us.

As the syntax parser runs through your code in the creation phase, it recognizes where you’ve created variables and functions, and sets up up the memory space for these before it has even run your code. This step is called hoisting.

Because of hoisting, we have access to variables before they are run, since they have space assigned to them in memory and decisions about them have already been made by the engine. One important thing to note is that hoisting does not mean the line of code was moved physically to the top of the file. The variables and functions exist in memory, and when the code actually executes line by line, we can access them.

However, variables are treated a bit differently than functions. In this example:

var a = 'hola!'

function b() { // some code}

Function b() is placed in memory in their entirety, with all the code and variables inside of it. For var a, the only thing placed in memory is the a, and in the next phase, when the code actually executes, it will know the value of a.

So what is the value of a at this phase? undefined

undefined is a special placeholder that all variables in Javascript are initially set to. It is a property that represents the primitive value undefined.

So this means if we console.log(a) at this phase, we would see the value of undefined.

Note — If we declare a var a, its initial value will be undefined. If, however, we declare b you will get back a b is not defined.undefined !== not defined!

Execution Phase

The next phase, the execution phase, is pretty simple to understand. In this phase, the engine will actually run your code line by line.

At this phase, with var a = 'hola!', if we console.log(a) we should get back hola! instead of undefined.

Let’s take the concepts we’ve discussed and talk for a moment about how functions are invoked with a simple example:

function b(){}

function a(){ b();}

a();

Once the parser is done with the code, the compiler will create the global execution context. Like mentioned previously, in this phase, the global object and this are created, and memory space is set up for a() and b(). Nothing inside of these functions will be run yet, since they haven't been invoked.

Once the last line a(); is hit, a new execution context is created, and it's placed in an execution stack. The execution stack will place contexts one on top of the other and will run whichever context is on top. a() then will have its own creation and execution phases, its own space for variables and functions, and then execute the code line by line. So in this case, when it hits b() inside of a(), it will create another execution context, and run that code.

So then the stack just pops the context at the top and continues from there. That means the lexical order of the code doesn’t really matter, nor does the surrounding code of the function calls. Remember that Javascript behaves in a single threaded manner, which means one command is being executed at a time. Synchronous means that code is executed one code at a time.

BUT AJAX stands for Asynchronous JavaScript + XML!! ⚡️

That is accurate. But it is a discussion for another day! In the next parts of the series, I will talk about AJAX in detail, and also discuss the awesomeness of callbacks, closures, and promises.

Understanding how the execution context works has helped me gain a deeper comprehension of the language that extends far beyond what frameworks have taught me. Stay tuned for part two!

If you want to chat Javascript (or Ruby! or whatever!) and see what it’s like to work for Stride, send me an email and let’s get some coffee ☕️ — on Stride :)