Table of content:

Up until now, we've been focusing on the global execution context and how it is created and executed. However, functions hold a special place in this context. In this section, we will delve into function invocation and the execution stack, introducing a crucial concept that lays the foundation for understanding advanced JavaScript topics.

In JavaScript, functions play a special role within the global execution context. Understanding how function invocation works and how execution contexts are managed is crucial for mastering advanced JavaScript concepts. In this blog post, we'll explore the process of function invocation and the execution stack, using a simple code example to illustrate these concepts.

Function Invocation: Running Functions in JavaScript

All this time, we've been talking about the global execution context and how it's created and executed. But we also mentioned that functions are special in regard to this.

The Process of Function Invocation

Here we'll talk about function indication and the execution stack. And we're going to introduce this concept that will be fundamental to understanding some very important advanced concepts in JavaScript.

Before we do that, though, we've rather casually used a word here, a word that sounds a lot more complex than it really is. Big word alert: invocation. That just means running a function or calling a function. So when we say we invoke the function or function invocation, we just mean, "Hey, run the function." In JavaScript, we do that by using parentheses. Put the name of the function, and then put parentheses. When you did that, you invoked the function. You told the JavaScript engine to run it.

Code Example: Understanding Function Invocation and Execution Stack

Now let's talk about what happens when you invoke a function in JavaScript. To do that, let's look at a simple example:

// Function 'b' does nothing
function b() {
  // No code here
}

// Function 'a' invokes function 'b'
function a() {
  b(); // Invoking function 'b'
  var c = 2;
}

// Invoking function 'a'
a();

var d = 4; // Line in the global execution context

This is a very simple example, but it helps us understand what's happening under the hood.

The Creation of Execution Contexts

Now here comes this fundamental very important concept.

Let's step through what we know is going to happen first if I put this code in a JavaScript file and ran it.

First of all, what's going to be created? That's right - a Global Execution Context. The parser will parse the code, and then the compiler, the program that's going to interpret your code, will start up and say, "Well, I need to create a Global Execution Context." It'll create the variable this, it'll create a global object (if you're in the browser, it will create a window object), and then it will attach these functions to it. It will set up the memory space for them in the creation phase of the execution context, that first phase. So b and a will be in memory, and then the code will be executed line by line.

The Execution Stack

Now, it won't execute anything in those functions because they haven't been invoked. But when it hits a() at the bottom and it says, "I'm supposed to invoke or call or run that function a" here's what actually happens.

A new execution context is created and placed on what's called the execution stack. And a stack is just what it sounds like, one on top of the other on top of the other. And whichever one is on top is the one that's currently running.

So anytime you execute or invoke a function in JavaScript, a new execution context is created and put on the execution stack.

Execution Context Lifecycle

So the execution context is created, just like the global one. It will have its own space for variables and functions. It will go through that creation phase, and then it will execute line by line the code within the function.

However, if I have another function invocation, it's going to stop at that line of code and create another execution context and run that code.

Now, in the case of b, there is no code to run, but this is how function invocation happens in JavaScript. Every function creates a new execution context which runs through the create phase and then executes the code line by line within the function.

Execution Order and the Global Execution Context

When a function finishes, because it's at the top of the stack, it will get popped off the stack, then a, and then back down to the Global context.

Notice that this doesn't matter. The order lexically doesn't matter. Nor does the rest of the code that happens to be surrounding those function calls.

For example, let's suppose we put a above b and we had some other code surrounding these function calls. That doesn't matter. Because even though lexically a is above b, remember what's happening. Both of those functions are already in memory during the create phase of the initial global execution context.

Code Execution within Execution Contexts

Those var c and var d that you see down below each of those function calls, let's talk about what's gonna happen.

First of all, a at the bottom will invoke a function a. So that will be the next put on the execution stack - the execution context for the function a.

Then, that becomes the currently running code, which means that the very last line at the bottom, var d below a, that's not going to be run yet. Because JavaScript is synchronous, one line at a time. And what's running is the current code within the current execution context, which is the one at the top of the stack.

So when a is at the top of the stack, it will start to run line by line. It hits that line where it invokes b. b creates a new execution context, so that becomes the top of the stack, and it is running line by line. It runs its single line of code there, and only when it finishes will we go back to finishing a.

Execution Context Stack and Flow

Why? Because when the function finishes, the execution context is what's called popped off of the stack.

So now, what's the current execution context again? a. So it runs the next line of code that hadn't yet been run inside that execution context, meaning that var c line.

And then, when a is finished, it's popped off the stack. And the next line of code that hasn't yet been run in the global execution context is run, which is the very last var d.

See how that works? Every time a function is called, a new execution context is created for that function. The this variable is created for that function. The variables within it are set up during the creation phase. And the code is executed line by line.

Conclusion

Understanding function invocation and the execution stack is crucial for comprehending the inner workings of JavaScript. By invoking a function, you create a new execution context that gets added to the execution stack, allowing the function's code to be executed line by line. When a function finishes, its execution context is popped off the stack, and the next context in the stack becomes the active one. This synchronous execution ensures the proper flow of code in your JavaScript programs.

In the provided code example, you can see how each function invocation creates a new execution context, and how the order of function definitions and the surrounding code does not affect the execution process. Keep these concepts in mind as you dive deeper into advanced JavaScript topics, as they form the foundation for further exploration.

Now that you have a solid understanding of function invocation and the execution stack, you're well-equipped to tackle more complex JavaScript concepts with confidence. Happy coding!