Functions & Execution Contexts

Functions are fun! If… you understand execution contexts.

Jamie Uttariello
5 min readApr 25, 2018

Every time a function is called in javascript an execution context gets created. Kind of like, “every time a bell rings an angel gets its wings.” But I digress.

To understand things like scope chaining, closure, recursion and just overall, why things happen the way they do in javascript, you first have to understand execution contexts.

The Basics of Execution Contexts

The first thing to understand is that every execution context is created in two phases: the Creation Phase, and the Execution Phase.

The second thing to understand is that the very first execution context that is created is the Global Execution Context.

And finally, every function that is called within a program will have its own execution context, contained within the Global Execution Context.

Now, let’s analyze all of this…

Phase 1: The Creation Phase

All execution contexts will have the same features. Those features are created in Phase 1 of building up the execution context, known as the Creation Phase. Here is list of features created before any line of code executes within a function…

  1. A reference to the object that called the function is stored in memory. In the case of the Global Execution Context, in a browser, that reference is of the window object.
  2. The keyword ‘this’ is created and stored in memory. Within the function, it will refer to the object that called the function.
  3. The function’s ‘outer environment’, its ‘scope chain’ is created.
  4. Its own ‘memory container’ for variables, arguments, and function declarations is created. Note that in the Creation Phase the JS Engine stores all variables and arguments with an initial value of ‘undefined.’

Phase 2: The Execution Phase

After the Creation Phase sets up the execution context, the JS Engine begins synchronously executing the code within the function, one line at a time, from top to bottom - this is Phase 2, the Execution Phase.

The Execution Phase is all about returning values. It evaluates expressions, which return values, and executes functions, which return values. The variables and arguments that were stored in Step 4 above will go from undefined, to the value the expression returns. For example…

// Example 1 - Variablesvar a = 25;//   Phase 1 - JS Engine stores 'a' as undefined in memory
// Phase 2 - JS Engine sees =, a JS Assignment Operator,
// so it evaluates the right side of the expression -
// from then on, 'a' will have a stored value of 25
// Example 2 - Variables w/ Function Expressionsvar sayHello = function(){
console.log('Hello');
}
// Phase 1 - JS Engine stores 'sayHello' as undefined in memory
// Phase 2 - JS Engine stores 'sayHello' as the anonymous function
statement on the right of the equal sign

Hoisting

It is important to understand that Step 4 above happens in the Creation Phase, that is, all variables are stored in memory before any function is executed. This process of storing variables before any code executes is called hoisting.

Hoisting sounds like it might mean that variables, arguments, and function declarations are lexically moved to the top of the code, but in reality, they stay exactly where they are. If you understand how JS works… that an execution context is created — in two phases… that in Phase 1, the Creation Phase, variables, arguments and function statements are stored in memory… THEN, in Phase 2, code is executed… then you understand hoisting.

Take this code for example…

console.log(a);var a = 25;console.log(a);

This code will store ‘a’ in memory as undefined BEFORE it executes the console.log(a) function. Here is how the JS Engine runs this code…

  1. Creation Phase. Creates global context and stores ‘a’ as undefined.
  2. Execution Phase. JS Engine starts from the top and sees console.log(a) in Line 1. It creates a new execution context and pushes it to the top of the Stack in the runtime environment.
  3. JS Engine then evaluates the code in that context. It sees a reference of ‘a’ so it searches the memory space in its execution context and does NOT see ‘a’. So it looks in the function’s outer environment, which is the Global Execution Context, and it finds ‘a’ in its memory space. (This process of looking in its outer environment’s memory space for a variable that was referenced within the function which was called, is called Scope Chaining.) It returns its value, which is ‘undefined’, so it prints it to the screen and pops that function off the Stack.
  4. The JS Engine, now back in the Global Execution Context, sees an equal sign in Line 2, so it knows to evaluate the right side of the equal sign, return a value, and change the stored value of ‘a’ from undefined to 25.
  5. The the JS Engine encounters Line 3 where console.log(a) is called again. Now we repeat Step 3, but this time ‘a’ is stored in the Global Execution Context as 25 so it prints that to the screen instead of undefined.

Here is another quick example using a function expression. Follow the steps above to understand why the code does what it does…

sayHello();    // will print 'TypeError, sayHello is not a function'console.log(sayHello)         // prints undefinedvar sayHello = function(){
console.log('Hello');
}
console.log(sayHello) // prints the function definitionsayHello(); // prints 'Hello'

However, when it comes to function declarations, that is, functions that are written as a statement, not as part of an expression, the entire statement is stored in memory in the Creation Phase. Because of that hoisting, if the function is called first lexically, it will work! Remember, lexical means ‘relating to words’ so when someone says where it is lexically, it literally means where the thing is written in the code.

sayHello();      // will print 'Hello'function sayHello() {
console.log('Hello');
}

To further our understanding of javascript, now that we understand how the execution context is created and how javascript runs, we can start looking at these more complex topics: Scope Chaining, Closure, Currying, Composing, Recursion. However, they may not seem so complex anymore!

--

--