javascript interview preparation cheat sheet
Everything about javascript Main topics
Table of contents
- Scope
- Types of Scopes in JavaScript
- Global Scope
- Explanation
Scope
The scope is the current context of execution in which values and expressions are "visible" or can be referenced. If a variable or expression is not in the current scope, it will not be available for use. Scopes can also be layered in a hierarchy, so that child scopes have access to parent scopes, but not vice versa.
In simple way,
Scope refers to the availability of variables and functions in certain parts of the code.
Types of Scopes in JavaScript
In JavaScript ,there are two types of scope.
Global Scope
Local Scope
A local scope can be further divided into two types,
Local Scope
Function Scope
Block Scope
let number=3; //Global Scope
// Local Scope
function sum(){ //Function Scope
const arr =[1,2,3];
let sum =0;
for (let i=0; i<arr.length; i++) // Block Scope
sum = sum+arr[i];
}
}
Global Scope
A variable declared at the top of a program or outside of a function is considered a global scope variable. Let's see an example of a global scope variable.
// program to print a text
let a = "hello";
function greet () {
console.log(a);
}
greet(); // hello
In the above program, variable a is declared at the top of a program and is a global variable. It means the variable a can be used anywhere in the program.
The value of a global variable can be changed inside a function. For example,
// program to show the change in global variable
let a = "hello";
function greet() {
a = 3;
}
// before the function call
console.log(a);
//after the function call
greet();
console.log(a); // 3
In the above program, variable a is a global variable. The value of a is hello. Then the variable a is accessed inside a function and the value changes to 3.
Hence, the value of a changes after changing it inside the function.
Note: It is a good practice to avoid using global variables because the value of a global variable can change in different areas in the program. It can introduce unknown results in the program.
Local Scope
A variable can also have a local scope, i.e it can only be accessed within a function.
Example 1: Local Scope Variable
// program showing local scope of a variable
let a = "hello";
function greet() {
let b = "World"
console.log(a + b);
}
greet();
console.log(a + b); // error
Output
helloWorld
Uncaught ReferenceError: b is not defined
In the above program, variable a is a global variable and variable b is a local variable. The variable b can be accessed only inside the function greet. Hence, when we try to access variable b outside of the function, an error occurs.
Function Scope
A variable declared inside a function resides in the function scope. The variable can be accessed from functions or blocks inside the function(i.e., nested functions) but not from the outside.
Block Scope
Variables declared inside blocks like for loops or inside curly braces { } with let or const are block-scoped variables.
if(number % 2 === 0) {
let even = number;
console.log("Even", even);
} else {
let odd = number;
console.log("Odd", odd);
}
console.log("Even", even); //even is not defined
console.log("Odd", odd); //odd is not defined
The variables even and odd are declared inside { } braces, they are in block scope. In the first diagram, the variable i declared inside the for loop is also a block-scoped.
Lexical scope
Lexical scope is the ability for a function scope to access variables from the parent scope. We call the child function to be lexically bound by that of the parent function. The diagram below outlines the supposed hierarchy that the lexical scope maintains in JavaScript.
Example
var a = 10; // variable a assigned to 10
var func = function (){ // outermost function
var b = 20;
console.log("a and b is accessible (outer):", a, b);
var innerFunc= function (){ // innermost function
var c = 30;
console.log("a and b and c is accessible (innner):", a, b, c);
}
innerFunc();
return;
}
func(); // invoke function func
console.log("only a is accessible (global):", a);
Output
a and b is accessible (outer): 10 20
a and b and c is accessible (innner): 10 20 30
only a is accessible (global): 10
NOTE: JavaScript uses a scope chain to find variables accessible in a certain scope. When a variable is referred to, JavaScript will look for it in the current scope and continue to parent scopes until it reaches the global scope. This chain of traversed scopes is called the scope chain
Scope Chain
The scope chain is how Javascript looks for variables. When looking for variables through the nested scope, the inner scope first looks at its own scope. If the variable is not assigned locally, which is inside the inner function or block scope, then JavaScript will look at the outer scope of said function or block to find the variable. If Javascript could not find the variable in any of the outer scopes on the chain, it will throw a reference error.
Let's take an example and go through this process step by step. Check the below code.
// Global variable
const userName = "Peter";
// Outer function
function calcAge(birthyear) {
const currentYear = 2021;
const age = currentYear - birthyear;
// inner block
if (age <= 60) {
var working = true;
const message = \`Peter is still employed!\`;
console.log(message);
}
// inner function
function yearsToRetire() {
const retirement = 60 - age;
console.log(\`${userName} will be retired in ${retirement} years!\`);
}
yearsToRetire();
}
calcAge(1975);
Single Thread
Javascript runs synchronously which means it has only one call stack that is used to execute the program and the block of code is execute one by one. which means that no matter how long the first take takes time to execute it will only proceed to next line only after the first line is executed 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.
// Executing Synchronously
function makeCoffee(){
console.log("Coffee is made");
)}
function boilEggs(){
console.log("Eggs is made");
}
function toastBread(){
console.log("Bread is toasted");
}
Call Stack
The call stack is used by JavaScript to keep track of multiple function calls. It is like a real stack in data structures where data can be pushed and popped and follows the Last In First Out (LIFO) principle. We use call stack for memorizing which function is running right now. The below example demonstrates the call stack.
function f1() {
console.log('Hi by f1!');
}
function f2() {
f1();
console.log('Hi by f2!');
}
f2();
"Hi by f1!"
"Hi by f2!"
Explanation
The steps and illustrations below explain the call stack of the above function.
Step 1: When the code loads in memory, the global execution context gets pushed in the stack. Step 2: The f2() function gets called, and the execution context of f2() gets pushed into the stack. Step 3: The execution of f2() starts and during its execution, the f1() function gets called inside the f2() function. This causes the execution context of f1() to get pushed in the call stack. Step 4: Now the f1() function starts executing. A new stack frame of the console.log() method will be pushed to the stack. Step 5: When the console.log() method runs, it will print “Hi by f1” and then it will be popped from the stack. The execution context go will back to the function and now there not any line of code that remains in the f1() function, as a result, it will also be popped from the call stack.
Step 6: This will similarly happen with the console.log() method that prints the line “Hi by f2” and then finally the function f2() would finish and would be pushed off the stack.
Hoisting
Hoisting is a very important process in JavaScript that’s made by the interpreter. The interpreter moves the declaration of functions and variables to the top of their scope, prior to the execution of the code. This feature is known as hoisting in JavaScript.
Variable Hoisting
Hoisting works with variables too, so you can use a variable in code before it is declared and/or initialized. However, JavaScript only hoists declarations, not initializations! This means that initialization doesn't happen until the associated line of code is executed, even if the variable was originally initialized then declared, or declared and initialized in the same line. Until that point in the execution is reached the variable has its default initialization (undefined for a variable declared using var, otherwise uninitialized). JavaScript, we can declare variables with const, let, and var. I will explain in detail each variable declaration type individually because the behavior is not the same when hosting.
var hoisting
Here we declare and then initialize the value of a var after using it. The default initialization of the var is undefined.
console.log(num); // Returns 'undefined' from hoisted var declaration (not 6)
var num = 6; // Initialization and declaration.
console.log(num); // Returns 6 after the line with initialization is executed.
Let and Const hoisting
Variables declared with let and const 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.
console.log(num); // Throws ReferenceError exception as the variable value is uninitialized
let num = 6; // Initialization
Class hoisting
Classes defined using a class declaration are hoisted, which means that JavaScript has a reference to the class. However the class is not initialized by default, so any code that uses it before the line in which it is initialized is executed will throw a ReferenceError.
Function and Class expression hoisting
The expressions evaluate to a function or class (respectively). They are typically then assigned to a variable or passed to other functions. In this case, the variable declaration is hoisted and the expression is its initialization. Therefore the expressions are not evaluated until the relevant line is executed.