Some Advanced Concepts in Javascript.

Some Advanced Concepts in Javascript.

In this piece I want to talk about three advanced JavaScript concepts: execution context, lexical environment, and closure.

In this piece I want to talk about three advanced JavaScript concepts: execution context, lexical environment, and closure.

This will be a long post. If you want to skip to the summary, scroll to the bottom of the page.

What is an Execution Context?

So, what is an execution context? Whenever you write some code, your code is in a space — that space is called the “execution context”. Imagine you wrote a simple calculator:

function cal(type, a, b) {
  if (type === 'add') {
    return a + b;
  } else if (type === 'subtract') {
    return a - b; 
  } else if (type === 'multiply') {
    return a * b; 
  } else {
    return a / b; 
  }
}

var four = 4;
var seven = 7;
cal('add', 4, 7);

In JavaScript, whenever a function is invoked, a new execution context is created on the execution context currently running. A newly created one is stored in the stack for execution contexts.

So, if we call cal(), the new context will be created and it will be pushed to the context stack. But, by default, there’s an already existing context in the stack — a global execution context.

global execution context

First the function cal is called and run so the new execution context is created. Then it is stored in the context stack. Then the control of the current execution context is transferred to the newly created one from, in this case, the global context.

An execution context is created whenever you call a function. When developing in JavaScript, you might have seen this error:

Call stack error Call stack error

The function a keeps calling itself recursively. Every time a calls itself, a new execution context about a will be created and stored in the stack. Since the memory stack’s storage space isn’t infinite, it overflows.

Now you know what an execution context is, but there is more to learn. We’ll talk about it further shortly.

A Lexical Environment

What happens when you run a function or when you declare a variable or a function? I barely explained that an execution context is created on every function calls and there’s a global execution context in the stack by default. An execution context is divided into three different areas.

Inside an execution context

The first two sections in an execution context — LexicalEnvironment and VariableEnvironment, are very similar, so I think I can call them just LexicalEnvironment. What LexicalEnvironment does is to keep track of variables, function names and associated values. In other words, if you declare a function foo like a figure above, then the LexicalEnvironment would look like this:

function foo() {
  var a = 10;
  function bar() {

  }
}
foo();

// When foo is called, a new execution environment 
// might look like this below
execution_environment: {
  LexicalEnvironment: {
    a: 10,
    bar: function() {}
  },
  ThisBinding: ...
}

You now know what LexicalEnvironment is and what it does.

Just as an execution context consists of three parts, LexicalEnvironment also consists of a few parts. It has anEnvironmentRecord — I will call it an environment record, and an outer lexical environment that you may think it’s scope.

When you declare a variable or a function, they are actually stored in its environment record. Chaining the value of property basically means chaining the value of a property that belongs to an environment record.

A reference to the outer lexical environment is also created when LexicalEnvironment is created. It directly links to the parent LexicalEnvironment, and JavaScript uses this value when it can’t find a property in the current LexicalEnvironment. If it still can’t find it in the parent LexicalEnvironment, then it, again, goes up to the parent LexicalEnvironment. This process doesn’t stop until it finds what it’s looking for or until nothing is connected to the LexicalEnvironment. The global LexicalEnvironment doesn’t have a parent's LexicalEnvironment. So, when JavaScript tries to look for something in the global LexicalEnvironment, a Reference Erroroccurs.

Example with figures

To understand this flow better, let’s take a look at this example:

var x = 1;
function foo() {
  var y = 2;
  function bar() {
    var z = 3;
    function baz() {
      console.log(z);
      console.log(y);
      console.log(x);
      console.log(w);
    }
    baz();
  }
  bar();
}
foo();
// 3
// 2
// 1
// Reference Error: w is not defined

The global LexicalEnvironment The global LexicalEnvironment

When JavaScript runs the code, the variable x and the function foo are declared in the global LexicalEnvironment. As I explained, the global’s outer doesn’t point to anything. When JavaScript meets foo() , it runs the function and the newLexicalEnvironmentoffoois created. Its outer link links to its parent’s globalLexicalEnvironment. This figure illustrates the whole relationship in the example code:

The entire relationship amongst LexicalEnvironments The entire relationship amongst LexicalEnvironments

You can see outer in each LexicalEnvironment points to the parent’s LexicalEnvironment.

When baz() is called, it looks for z, y , x , and w.

The workflow when z and w are looked for The workflow when z and w are looked for

Like this flow, finding the variable y and x does the same work — checking whether or not to exist the value in the current LexicalEnvironment and moving to the parent’s one if there’s no variable. But for w , it doesn’t exist anywhere in the codes so we end up with a reference error.

This is what you normally heard, a scope chain. But remember, the outer environment, connecting to the parent’s environment, is determined when the function is declared, not when it’s invoked (Click here to get further information). For instance, guess the return value of bar().

var x = 1;
function foo() {
  var x = 2;
  bar();
}

function bar() {
  console.log(x); 
}

foo(); // 1

Why is the result of foo() 1 and not 2? As I said, the outer reference is the parent’s LexicalEnvironment, not the function surrounding it.

ThisBinding

The reference inside the execution context, ThisBinding, determines how the function is called. I’ll talk about this topic more in another piece.

Back to Execution Context

Now, you know what are in an execution context — LexicalEnvironment and ThisBinding. There are actually two kinds of execution context — global execution context and function execution context.

The global execution context is the execution context for the global object in JavaScript, which is the root of everything. What it contains are several objects. One of them is window — when JavaScript parses and interprets your script, it actually runs this first. (Of course, this is not exactly how JavaScript works).

<script>
  window = {
    ClipboardCopyElement: class ClipboardCopyElement,
    CodeMirror: f Ea,
    DetailDialogElement: class DetailDialogElement,
    ...
  };

  GlobalExecutionContext: {
    LexicalEnvironment: {
      window: window,
      outer: null
    },
    ThisBinding: window
  }
</script>

That’s why you could use window.document or window.setTimeout, since they are all in the LexicalEnvironment of the global object.

What about a function execution context? It’s just like a global execution context but no window or other global objects exist inside and it is created when a function is called. What the global execution context and function execution contexts have in common is that they both have two phases at runtime: creation and execution phases. In the creation phase, variables and functions are declared:

var x = 1;
function foo() {
  var x = 2; 
  function bar() {
    var x = 3; 
  }
}
console.log(y);
var y = 3;

foo();

The first step on running the code is that the global execution context is created. The control of action is in the creation phase.

The creation phase The creation phase

In the creation phase, variables are set by undefined by default. functions, on the other hand, are assigned by a function — like foo in the example above. The thing to note is that y is also defined as undefined as well, even though it’s declared after console.log . This symptom is called “hoisting” in JavaScript. Hoisting means variables and functions are declared and assigned with the default value, normally undefined , before the execution phase.

When the control moves to the execution phase, it runs every piece of code from the top. The first statement that will be executed is console.log(y) and it prints undefined out. Then y is set to three. The next step is to run foo(). When a function is called, a new execution context is created and pushed into the call stack.

The creation phase for a function The creation phase for a function

When a function is called, a function execution context is made. Then its creation phase starts first. The LexicalEnvironment of the function execution context defines all of the variables it needs. The special object, arguments, is a part of variables that are defined in every function LexicalEnvironment. You can see there’s a function bar(). Then the bar is invoked — its execution context will also be stored in the stack after being created.

Once all of the codes in a function are executed, its execution context is removed from the stack.

In this video, the speaker does a good job explaining the workflow of execution context switching in JavaScript.

Closures

I explained that LexicalEnvironment also has an outer environment that refers to the parent’s LexicalEnvironment. Take a look at this example:

var x = 1;
function foo(y) {
  return function(z) {
    return x + y + z;    
  }
}

var f = foo(2);

If you run this command on the web console, you’ll see this:

console.dir(f);

JavaScript Visualizer JavaScript Visualizer On above is what you can see from the google console and under is what you can see from the JavaScript Visualizer — the web page you can see here.

So, what happened? When the function foo was executed, it returned a new function. f now has the return value of foo . But in f , there’s a new scope object, named Closure. Even though the execution context of foo was removed from the stack, the referencing chains are still alive by the variable f . Then what if we execute f , now which is a function?

f(5);

An execution context in the closure Then the new execution context will be created like the picture above. The reason why z isn’t in the closure scope, is because it’s a property of the function that f ran, which is alive in the current execution context.

Once return x + y + z; is run and the function is finished, the execution context for f will be gotten rid of, and the closure will also be gone.

MDN defines closure:

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function.

Closure is a function that allows you to access to the parent function scope, even though it’s been removed from the execution context stack.

Final Summary

That was a long story to explain what execution context, LexicalEnvironment, closure, etc. Basically, when JavaScript runs codes, it creates a space for storing and managing variables and functions. It keeps track of the names and changes. Whenever a function is created, JavaScript makes this spaceand puts it on the top of the stack, where previously existing those spaces are stacked from the bottom. This space is called the execution context.

There are two execution contexts in JavaScript — the global execution context and the function execution context. An execution context is consist of LexicalEnvironment and ThisBinding. LexicalEnvironment is the place where variables and functions are actually stored and managed. ThisBinding is the reference for thisbut we didn’t cover that here.

JavaScript has two phases when it comes to managing variables and functions — creation phase and execution phase. During the creation phase, variables are declared but set by the default value, normally undefined, while functions are declared and initialized at once. After the creation phase, the action control moves to the execution phase, where all of the codes are executed, one by one, from the top of the file. If a function is invoked during this phase, a new execution context for that function will be created and stored in the stack. If there are too many contexts in the stack, we also confirmed that reference errors occur.

Even though an execution context is deleted from the stack once it has run all the codes inside, a reference to the function is alive when the original function returns a new function that uses a variable out of its scope. Then, the link to the outer function won’t be deleted until its codes are executed and completely removed from the stack. This is called Closure. Closure is a function that allows you to access the parent’s function scope, even though its execution phase is finished.

javascript programming

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Learning JavaScript: Development Environments for JavaScript Programming

One of the nice things about learning JavaScript these days is that there is a plethora of choices for writing and running JavaScript code. In this article, I’m going to describe a few of these environments and show you the environment I’ll be using in this series of articles.

Learning JavaScript: Data Types and Variables

To paraphrase the title of an old computer science textbook, “Algorithms + Data = Programs.” The first step in learning a programming language such as JavaScript is to learn what types of data the language can work with. The second step is to learn how to store that data in variables. In this article I’ll discuss the different types of data you can work with in a JavaScript program and how to create and use variables to store and manipulate that data.

[ Professor JavaScript ]: Introduction

Professor JavaScript is a JavaScript online learning courses YouTube Channel. Students can learn how to develop codes with JavaScript from basic to advanced levels through the online courses in this YouTube channel.

From imperative to declarative JavaScript

In this post, I will explain why declarative code is better than imperative code. Then I will list some techniques to convert imperative JavaScript to a declarative one in common situations.

JavaScript Memory Management System

The main goal of this article is help to readers to understand that how memory management system performs in JavaScript. I will use a shorthand such as GC which means Garbage Collection. When the browsers use Javascript, they need any memory location to store objects, functions, and all other things. Let’s deep in dive that how things going to work in GC.