JavaScript Interview CheatSheet

JavaScript Interview CheatSheet

ยท

8 min read

Hi guys, in this article we will be learning about the most common and important questions that are asked in a JavaScript Interview.

Let's start with the topics.

Single Thread Programming Language

We have heard that JavaScript is a single-threaded language. Now the question arises what is Single Threaded ?

JavaScript is implemented by JavaScript engines like:

  • V8 Engine for Google Chrome
  • Spider Monkey for FireFox
  • JavaScriptCore for Safari

These engines are made up of two components:

  1. Heap Memory
  2. Execution Context Stack

image.png

Heap Memory:

In heap memory Function references, objects, and all the other components like variables etc are stored, Heap is a space inside the PC where all this data is stored.

Call Stack:

Now comes the call stack also know as Execution Context Stack, as we have seen in the execution context stack, first Global execution context gets created, then when the engine reads any function in the code it creates the Functional execution context above the global execution context and when this function gets completed it pops off the global execution context.

gif2.gif

Stack follows LIFO - Last In First Out. And in JavaScript we have only one call stack in the engine thus, the function does not have any other means to get executed, it has to follow LIFO.

Thus we can say that JavaScript is a single-threaded language and it is synchronous in nature.

Scope

There are two types of scope:

  1. Global Scope
  2. Local Scope

image.png

Whenever you define something, like a variable, you want it to be inside certain boundaries because sometimes it does not make sense to have a variable outside a function. For example, if you have a function that calculates the area of a rectangle using two inputs height and width, and returns the area, then you need the variable area inside the function only and there is no need for the area outside the function.

let height = 20;
let width = 10;

function calculateArea() {
  let area = height * width;
  console.log(area);  // area = 200
}

calculateArea();

This function will print the area, as expected.

But, what if we want to print the area again, we can just directly do console.log(area) because we already have the area of the rectangle inside the area variable, right? Let's see.

let height = 20;
let width = 10;

function calculateArea() {
  let area = height * width;
  console.log(area);  // area = 200
}

calculateArea();

console.log(area);  // ReferenceError: area is not defined

But this gave an error, did we do something wrong? No !!!, this is how the scope in JavaScript works. This accessibility of elements in JavaScript is known as Scope.

Scope in JavaScript is determined by the function or the block of code wrapped inside { }.

For the above example, the scope of the area variable was only inside the function calculateArea(), outside the function area is inaccessible.

The scope is like till where an element is relevant, variable area is relevant only in the function calculateArea(), thus its scope is inside function calculateArea() only and not outside it.

image.png

Because the scope is limited to the function only, we can define the same variable(area) inside multiple functions and it will not cause an issue. Let's try that.

image.png

Even though area was defined at two different places, still it did not give any error because the scope of the first area was only inside the function calculateArea() and the second area only had scope inside the function calculateAreaSquare().

Now, let's take a look at Nested Scope.

Nested Scope

When we have one scope inside another scope it creates a nested scope.

function outerFunction() {
  let outerVariable = "I am outer function";

  function innerFunction() {
    let innerVariable = "I am Inner Variable";
    console.log(outerVariable + " and " + innerVariable);
  }

  innerFunction();
}

outerFunction(); // "I am outer function and I am Inner Variable"

image.png

Inner Scope can access the variables of the Outer Scope but the same is not possible vice-versa. It is similar to how a living being inherits properties from their parents. A child inherits from parents but parents do not inherit from the child.

Similar to that, in the above example we can see that outerVariable is inside function outerFunction() (parent function) but still outerVariable is accessible inside function innerFunction() (child function)

Thus we can conclude two things,

  1. Scopes can be nested
  2. Elements of the outer scope are accessible inside the inner scope but not vice-versa

Now, as we have understood the scope and nested scope, let's start with Lexical Scoping.

Lexical Scope:

In simple terms, Lexical scope is the place where the item got created.

Example.

let myName = "Dan";

function call() {
  console.log(myName);
}

call();

In the above example variable myName is called inside function call() i.e. local scope, but as we know Lexical Scope is the place where the item got created, not called, and in this example, the variable was initialized in Global Scope, thus the Lexical scope of variable myName is Global Scope.

Let's look at another example:

function call() {
  let myName = "Dan";
  console.log(myName);
}

call();

Here Lexical Scope of myName is call() functional's local scope because myName is created inside the function call().

Thus we can say that Lexical Scope determines the access to the elements in different scopes.

Scope Chaining

So, as we have seen Lexical Scoping decides the accessibility of variables, and that process is known as scope chain.

Scope Chain means nothing but looking for the required variable first in the local scope and if JavaScript engine does not find it there then it looks for it in the outer scope. Like how qualities are inherited from grandparents to parents and from parents to children. Similarly, a function can access elements of its parent scope a global or local/functional scope and that parent function can access the elements of its parent scope global or functional/local scope.

Let's understand this by an example.

// global scope
let globalVariable = "Global";

// outer function scope
function parent() {
  let parentVariable = "Parent variable";

  // inner function scope
  function child() {
    let childVariable = "Child Variable";

    console.log(`I am ${globalVariable}, I am ${parentVariable} and I am ${childVariable}`);
  }
  child();
}
parent();

image.png

Here when the child() function runs, it looks for globalVariable, and as it is not in the local scope Js Engine searches for it in the outer scope i.e. the parent() function scope but globalVariable is not present there also thus Js Engine goes to the globalScope where the variable is present.

We can see a chain is formed from child() -> parent() -> global. This is how a scope chain is formed.

Call Stack OR Execution Context Stack.

As we know Global Context gets executed first and when the Js engine finds any function it performs the Functional Context Execution.

gif.gif

First, the Global Context Execution is done then when the Js engine finds function function1() it performs the Functional Context Execution. Then in the function1() Js engine finds function2() thus it executes FCE for function2 and as the execution of function2() is completed it is removed from the stack, then after the execution for function1() completes, it also gets removed from the execution stack and finally after the whole code is executed Global Context also gets removed from the stack.

This is how the call stack works in JavaScript.

Hoisting

Hoisting is the process where JavaScript enables us to use variables and functions even before they are initialized.

During scanning phase of execution context JavaScript engine scans for all the variable and functions and put it at the top of their scope.

When the variables are scanned during scanning phase, only declaration is done but those are not initialized.

// Variable lifecycle
let a;                  // Declaration
a = 100;             // Assignment
console.log(a);  // Usage

For variables with var, default initialization is undefined till the variable is actually initialized. For the variables with let and const default initialization is uninitialized and thus when variables with let and const are used before initialization it gives Reference error.

Let's take a look at some examples.

Example 1

console.log(a);  // undefined

var a = 10;

console.log(a);  // 10

In the above example when the first line is executed, it does not give error because var a is stored in global scope an it has its default declaration as undefined. In the second line var a is initialized and when third line is executed it returns 10.

Example 2

console.log(a);  // Reference error

let a = 10;

Hoisting does not work same for let and const. For such variable if they are used before initialization it returns reference error because while scanning phase the variable declaration is not stored with initial declaration as undefined.

The reason behind this reference error is TDZ-Temporal Dead Zone, we have discussed about this topic in another article.

Execution Context and TDZ

The location at which the variables are stored before they are initialized is called TDZ Temporal Dead Zone. The

Function Hoisting.

Functions can also be hosted. Function hoisting allows us to call a function before it is defined.

greet();

function greet() {
  console.log("Hello There");
}

Here we can see that, function is called before function declaration and it does not returns error. But this not same if function is stored in a variable

hello();  // TypeError

var hello = function greet() {
  console.log("Hello There");
};

Hoisting can be beneficial in cases like all the functions can be called at the beginning and functions can be defined at the end which makes it easy for the person to focus on the execution rather than focusing on the other stuff.

Thanks for reading this article, hope you found it helpful. ๐Ÿ˜ƒ

ย