Deconstructing JavaScript Execution: Creation Phase(Part 1)

Deconstructing JavaScript Execution: Creation Phase(Part 1)

So far, we have delved into the?mechanics of the JavaScript engine, particularly its adept management of execution contexts. Now, let's delve deeper and comprehend the process by which the JavaScript engine creates execution contexts. Additionally, we'll unravel the concept of the scope chain, its relationship with variables, and the intricacies of the "this" keyword.

Brace yourself for an enlightening journey as we navigate through the intricate aspects of JavaScript.

Note: This content has been meticulously crafted, recognizing the significant importance of understanding execution context in our comprehensive "The Depth of JavaScript" series.

Before we proceed, let's first understand the two types of execution contexts in JavaScript: Global Execution Context (GEC) and Function Execution Context (FEC)

  1. Global Execution Context (GEC): Created when a script file is received, it serves as the default Execution Context for code outside of functions. Each JavaScript file has only one GEC.
  2. Function Execution Context (FEC): When a function is called, the JavaScript engine creates a Function Execution Context within the GEC to execute the code within that function. Multiple FECs can exist during script runtime, as each function call has its own FEC.

No alt text provided for this image

Now, Let's Dive Right In: The Creation of Execution Contexts

To comprehend the creation of execution contexts, we observe a two-phase process: the Creation Phase and the Execution Phase.

Creation Phase: During this initial phase, the JavaScript engine sets up the necessary components for the execution context.

Execution Phase: Once the creation phase is complete, the execution phase begins. Here, the JavaScript engine executes the code line by line within the execution context. It assigns values to variables, calls functions, and performs other operations specified in the code.

Let's take a detailed look at both.

Creation Phase

During the creation phase of an execution context, the JavaScript engine completes essential tasks to prepare for code execution. Here are the key steps involved:

  1. Variable Object (VO) Creation
  2. Creation of the scope chain
  3. Determining the value of the 'this' keyword

Creation Phase: Variable Object (VO) Creation

The first step in the creation phase involves the creation of the variable object (in the case of a function context) or the lexical environment (in the case of a block context). Let's dive deeper into each of these concepts:

The variable object consists of three main components:

  • Function declarations: Any function declarations within the function body are added to the variable object. This allows you to call these functions even before they appear in the code, a behavior known as function hoisting.
  • Formal parameters: The formal parameters of the function, i.e., the variables declared in the function's parameter list, are also part of the variable object.
  • Variable declarations: Any variable declarations (using the var keyword) within the function scope are added to the variable object. However, the assignment (initialization) of these variables is not performed during the creation phase.

It's important to note that with the introduction of the let and const keywords in ECMAScript 2015 (ES6), block-scoped variables are not included in the variable object of a function context. Instead, they are handled within the lexical environment of the block where they are declared.

Lexical Environment (Block Context):

In a block context (such as within an if statement or a for loop), the lexical environment is created during the creation phase. The lexical environment serves as a container for block-scoped variables (variables declared with let and const) and other lexical declarations within the block's scope.

Hoisting

Hoisting is a behavior in JavaScript where variable and function declarations are moved to the top of their respective scopes during the creation phase. This means that you can use variables and call functions before they are actually declared in the code.

No alt text provided for this image

- Variable Hoisting: When variables are hoisted, their declarations are moved to the top of their scope, but not their assignments. This means you can access and use variables before they are declared, but their initial values will be undefined until assigned.

- Function Hoisting: Function declarations are fully hoisted, meaning you can call functions before they are declared in the code.

For example:

console.log(x); // Output: undefine

var x = 10;

console.log(x); // Output: 10


sayHello(); // Output: "Hello"

function sayHello() {

?console.log("Hello");

}        

In the example above, even though the variable `x` is accessed before its declaration, it doesn't throw an error. Instead, it returns `undefined` until the assignment `var x = 10` is reached. Similarly, the function `sayHello()` is called before its declaration due to hoisting.

Creation Phase: Creation of the scope chain

Along with creating the variable object (for function contexts) or the lexical environment (for block contexts), the JavaScript engine also creates the scope chain.

The scope chain is a series of nested variable objects (also known as activation objects) that represent the scopes containing the function. Each variable object has a reference to its outer environment (parent scope), forming a chain. This chain allows variables and functions to be accessed and resolved during the execution phase.

Scope Chain (Function Context): When a variable is accessed within a function, the JavaScript engine first looks for it in the local variable object (function's own variable object). If the variable is not found, it traverses the scope chain, moving to the outer environment, until the variable is found or until it reaches the global scope.

Lexical Environment (Block Context): In a block context, such as within an if statement or a for loop, the scope chain is created using the lexical environment. The lexical environment serves as a container for block-scoped variables (variables declared with let and const) and other lexical declarations within the block's scope.

No alt text provided for this image

Closure

When a function is defined within another function, the inner function forms a closure over the outer function's scope. This means that the inner function has access to the variables, parameters, and functions of the outer function, even when the outer function has completed execution.

No alt text provided for this image

Closures enable the concept of data encapsulation and private variables in JavaScript. They are widely used in scenarios like creating private variables, implementing modules, and handling asynchronous operations.

Here's an example to illustrate closure:

function outer() 

?var outerVariable = "I'm from the outer function";

?function inner() {

??console.log(outerVariable);

?}

?return inner;

}


var closureExample = outer();

closureExample(); // Output: "I'm from the outer function"{        

In the example above, the inner function `inner()` forms a closure over the `outer()` function's scope. Even after the `outer()` function has finished executing and its local variable `outerVariable` is technically out of scope, the closure retains access to `outerVariable` and can still access and log its value.

Creation Phase: 'this' Keyword Assignment

The value of `this` depends on how a function is called and is set right before the execution phase begins.

Here are the rules for determining the value of `this`:

Global Scope: When a function is called in the global scope (outside of any object), the `this` keyword refers to the global object. In a browser environment, the global object is `window`, while in Node.js, it is `global`.

console.log(this); // Output: [object Window] (in a browser)        

Method Invocation: When a function is called as a method of an object, the `this` keyword refers to the object itself.

const person = 

?name: "John",

?greet: function() {

??console.log("Hello, " + this.name);

?}

};

person.greet(); // Output: "Hello, John"        

In the example above, when `person.greet()` is called, `this` inside the `greet()` function refers to the `person` object.

Constructor Invocation: When a function is called with the `new` keyword to create an instance of an object (constructor invocation), the `this` keyword refers to the newly created instance.

function Person(name) 

?this.name = name;

}

const john = new Person("John");

console.log(john.name); // Output: "John"{        

In the example above, `this` inside the `Person` constructor refers to the newly created instance (`john`) and allows setting the `name` property for that specific instance.

Execution Phase

In part 2 of this series, a detailed explanation of the execution context in JavaScript will be provided.

The JavaScript engine performs other operations specified in the code. This process is facilitated by the JavaScript engine's components, including the call stack, event loop, and various Web APIs. For a more comprehensive understanding of these components and their role in JavaScript's runtime environment, i invite your to check my previous articles in "The Depth of JavaScript" series, where we explored the mechanics of the JavaScript engine, the call stack, the event loop, and related concepts.

So, join me ?? on this journey as we delve into the exciting world of advanced JavaScript concepts and stay informed about the next post series outlined in the roadmap above.

Thank you for your continued support and interest in my newsletter.


#advancedJavaScript

#javascriptConcepts

#javascriptdevelopers

#javascriptpro

#exploringtheDepthsofJavaScript

#guideto28AdvancedConcepts



要查看或添加评论,请登录

社区洞察

其他会员也浏览了