Dissecting JavaScript I

Dissecting JavaScript I

Basic Working of JS

Introduction

JavaScript is an interpreted programming language used to create interactive and dynamic websites. JavaScript was created by Brendan Eich in May 1995, within 10 days. Eich worked at Netscape and implemented JavaScript for their web browser, Netscape Navigator. Initially, it was "LiveScript" but later capitalized on the popularity of Java at that time.

Let's now understand the workings of JavaScript first...

Workings of JavaScript

Execution Context

Everything in JavaScript works inside an execution context. It is the environment where the JS code gets executed. An execution context consists of two parts:

  • A variable environment.

  • A Thread of Execution.

As JavaScript is a synchronous, single-threaded language, JS engine executes the program sequentially, one line at a time. So each time a JS program runs an execution context is created.

suppose, we have a simple JS program:

var n = 2;
function square(num){ // num is the parameter
    var ans = num * num;
    return ans;
}
var square2 = square(n); // n is the argument passed into the function
var square4 = square(4);

Whenever this program is executed a global execution context is created, which is firstly followed by the memory creation phase & then the Code execution context. Refer to the diagram below for a better visualization of how JS executes a program.

Step 1. Memory Creation Phase:

In this phase memory space is allocated for the variables used in the program initially all variables are initialized with undefined.

Step 2. Code Execution Phase

Code is executed line by line by the JS engine, in this phase individual variables are assigned with their actual value, and also functional execution contexts are created whenever there is function invocation. Whenever the JS engine encounters a return statement it returns the whole control back to the execution context where the function was invoked.

Call Stack

The call stack is used to manage the flow of function calls and their execution in a program. It keeps track of the active function calls in a program and their execution context. In JavaScript the call stack operates on a Last In, First Out (LIFO) basis, meaning that the most recently called function is the first one to be executed and completed. It is also known as the Execution context Stack, Runtime Stack, Program Stack, or Control Stack.

Hoisting

Hoisting is a phenomenon in JavaScript by which you can access the variables & functions even before you have initialized them in the program.

Here in the example given below the output of console.log(x) is "undefined" as when the JS engine runs the program for the first time memory space is allocated for each variable and initially except for the function declaration all are initially set to "undefined". As console.log(x) is coming before initializing the x with its actual value 8, we are obtaining "undefined" as a result.

Arrow function is not hoisted in JS as it is treated as a normal variable by the engine.

Window

The window is a global object, which is created along with the Global execution context in browser environment. It is the top-level scope and contains properties and methods related to the browser window, such as the document, location, history, and more. In JS window feature is used to access browser features and event handling.

var x = 10;
function myFunction() {
    console.log("Hello, world!");
}
console.log(window.x); // 10
window.myFunction(); // Hello, world!

Scope

Scope refers to the context in which variables, functions, and objects are accessible within the JS program. It is crucial to understand how variables are accessed and how their values are managed throughout the execution of a JavaScript program.

There are mainly two types of scopes in JavaScript :

  • Global Scope: These variables are accessible from any part of the program, usually variables written with the var keyword in any part of the program have global scope, and variables declared with let keyword outside any block have global scope.

  • Local Scope: Variables declared with let & const keywords inside any block have a local scope that is they are accessed only in the context where they are created and in contexts within them.

Lexical Environment

Whenever an execution context is created a lexical environment is also created along with it. The lexical environment is the local memory plus the lexical environment of its parent. Thus the local memory bundled together with the parental lexical environment is referred to as the Lexical environment of a context.

And the chain of all lexical environments and the parent reference forms the scope chain.

Temporal Dead Zone

In JavaScript Temporal Dead Zone refers to the period between entering into a scope and the actual declaration of a variable. If someone attempts to access a variable during the temporal dead zone a reference error will be obtained.

console.log(num);
let num = 18;

Types of Errors in JS

There are mainly 3 types of errors in JavaScript, viz:

  1. Reference Error: This occurs when you try to access a variable or object when it is not even declared. Variables declared with the var keyword are an exception to this as they get assigned with undefined in the memory creation phase.

  2. Syntax Error: The error obtained when the basic syntax of the JS is violated, such as misspelling a keyword, a mistake in punctuation, or reassigning the same variables within the same scope.

  3. Type Error: This typically happens when you try to use a value in a way that is not supported by its data type, or when you attempt to call a method on an object that does not exist or is not callable.

Closure

A closure is the combination of a function bundled together(enclosed) with references to its surrounding state i.e. closure is a function with its lexical environment.

Closure = Function + Lexical Scope

In other words, a closure gives you access to another function's scope from an inner function. In JS closures are created every time a function is created.

Take a look at this program and try to predict its output before actually seeing it:

function x(){
    var a = 12;
    function y(){
        console.log(a);
    }
    return y;
}
var z = x();
console.log(z);
z();

The function x contains a variable a and another function y, which is also returned at the end of the function x. The function y logs variable 'a' in the console, which is in the scope of its parent. z is another variable that stores the invocation of the function x. And if we later invoke z which contains the function y we get 12 printed in the console as 'a' was stored in the lexical environment of y. This is what closure it, function bundled together with its lexical scope.

This marks an end to this blog the first of the Dissecting JavaScript Series the next part will discuss functions, different jargon related to them, callback functions, Event Listeners, Browser features, JS engine in detail, Callback hell, the need for Promises, async - await syntax any many more concepts in detail.

Conclusion

In conclusion, JavaScript is a versatile programming language that plays a crucial role in creating interactive and dynamic websites. Understanding the core concepts of JavaScript, such as execution context, hoisting, scope, and closures, is essential for writing clean, efficient, and bug-free code.

As we continue in this JavaScript series, we'll discuss topics like functions, callback functions, event listeners, browser features, and more. By building on these foundational concepts, we'll explore advanced JavaScript topics.

Hope you enjoyed this blog and liked it. Do share your valuable feedback if possible this will help me to improve myself.

Stay tuned for the next part of the Dissecting JavaScript Series, where we'll continue our journey into the fascinating world of JavaScript programming.