JS Interview CheatSheet

JS Interview CheatSheet

ยท

6 min read

โ“ Scope ๐Ÿ“ฅ

Scope defines the area, where functions, variables and other things are available or can be accessed. In layman's terms, scope means where to look for things, what things I can use and what I cannot!

Let's take an example, here we are defining a variable inner inside a block ({...}) and we are trying to access it both inside the block as well as outside the block.

{
    let inner = "I am inside a block";
    console.log(inner);
}

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

Here as variable inner is declared inside a block, we are unable to access it outside the block or we can say, the scope of variable inner is limited to that block only, we cannot use it outside that block.

How are scopes determined?

To answer this question we need to figure out how JavaScript runs our code. Abstractly speaking, JS engine runs our code in two phases.

  • Compilation/Scanning/Parsing of code
  • Execution

The execution part is simple, it just runs our code line by line. But what is parsing?

Parsing of code means, that JS, before executing the code, scans the whole code and does multiple things including optimization, memory allocation, etc. One of which is setting scopes for our variables. Let's see how it does that with a code snippet and a diagram.

// Global Scope
var names = ["Prateek Budhiraja", "Anirudh", "Hitesh Choudhary", "Anurag"];

function getFullName(list) {
    // Function getFullName's scope

    let fullName = [];
    for (let name of list) {
        // For scope

        if (name.includes(" ")) {
            fullName.push(name);
        }
    }
    return fullName;
}

console.log(getFullName(names));

scope.png

So what complication does is, it categorises every element according to the scope!

Scope/Access Rule:

  • If the variable is not declared in the current scope, the next outer/enclosing scope will be consulted and this process of stepping out one level of scope nesting continues until either a matching variable declaration can be found, or the global scope is reached and there's nowhere else to go.

For example in our above code:

  • In the global scope, we can only access variables we declared in the global scope. i.e. names.
  • In function scope, we can access everything we declared in the function scope, and along with it, we can also access variables of the global scope. i.e. names, fullName, list.
  • Similarly in for scope, we can access everything from its scope, its parent, i.e. function and also from the global scope. So from for, we can access names, list, fullName, name.

scop2.png


โ“ Hoisting

Hoisting is a process where javascript moves our functions, variables and class declarations to the top of their scope before the execution of the program, which we can safely call our function before they are declared. Example:

sayHello();

function sayHello() {
    console.log("Hey, friends ๐Ÿ‘‹");
}

We can also hoist variables but they are usually avoided as they tend to give unexpected errors. Example:

if (isLoggedIn) {
    console.log("Show dashboard");
} else {
    console.log("Show login page");
}

var isLoggedIn = true;

So the above code runs, just the problem is even though we see that we assigned true to the variable isLoggedIn, the else part is getting executed, this is because isLoggedIn variable is scanned and made available so it is not giving any errors, but it is assigned a value undefined, and as undefined is a falsy value, therefore the condition fails and it executes else part.

hoisting.png

Rules for hoisting

  • Function declarations are scanned and made available.
  • Variable declarations are scanned and made undefined.

We have seen variables declared with var but if we are declaring variables with let and const, they are also hoisted but, unlike var, are not initialized with a default value. An exception will be thrown if a variable declared with let or const is read before it is initialized.

Example using both the concepts (scope and hoisting)

function sayHello() {
    let greetings = "Hello";

    {    // ๐Ÿ‘ˆ scope starts
        greetings = "hey";     //ReferenceError: Cannot access 'greetings' before initialization
        let greetings = "Hola";
        console.log(greetings);
    }

    console.log(greetings);
}

sayHello();

We got that error because the greetings variable is used (the code inside {...}) before its being initialized in that scope, even though it is declared/initialized in the outer scope, because it only consults the outer scope when the variable is not in the current scope, but as it is in the current scope, it fails!


โ“ JS is SingleThreaded

JavaScript is a synchronous single-thread programming language. We all heard it, we all read it, and it is the first line someone says while introducing javascript! But what does it means?

It simply means that JS will execute one statement at one time. It picks up one line, executes it and only goes to another line when the first line finishes its execution.

synchronous.png

We can visualize it as a memory stack, one line of code comes, it executes and it gets pops out of the execution context, or a big function comes on it gets executed and then it goes away and so on.


โ“ Call Stack

Callstack is nothing but a place where javascript keeps track of the execution of the code. With it, we can see which line of code or function is currently running, what will happen if this function ends, or what will happen if a function calls another function etc.

Let's take an example:

function calculateTip() {
    return 5;
}

function payBill(amnt) {
    let getTip = calculateTip();
    return `Total bill is ${amnt + getTip}`;
}

console.log(payBill(100));

The above is a simple JS program, which has 2 functions, one is payBill which is calling another function, called calculateTip, let's see how JS will execute this.

  • Java Script will first scan the whole code and will make the functions available for use.
  • It will encounter a function call (payBill(100)) it will add payBill function to the call stack.
  • Now the function will start it's execution.
  • While executing the function, it finds a function call for calculateTip().
  • We already have a function in the call stack, but as we get another function call, javascript will add calculateTip to the call stack. And as javascript is a single-threaded language, calculateTip function will start executing and payBill will be halted.
  • calculateTip finishes its work and returns some results. As soon as javascript encounters thereturn statement, it returns the value and javascript will remove calculateTip from the call stack.
  • Now we are back to our payBill function, now javascript also keeps track of where we need to resume, so instead of executing the function again, it knows from where we need to resume the execution.
  • After encountering the return statement in payBill javascript will return the value to the place from where the function was called and it will remove it from the call stack.

callstack.png

callstack1.png

I hope you learned something new, if you wish to read more about then, you can refer to the links below.

Happy Learning ๐Ÿ’ซ

Resources

ย