Javascript part two : whosgeek

Javascript part two : whosgeek


Understanding Scope in JavaScript

One of the most important concepts every JavaScript developer should understand is scope.

Many strange bugs in JavaScript happen because developers do not fully understand where variables can be accessed and where they cannot.

Think of scope as the visibility area of a variable.

A variable can only be used inside the area where it is visible.

Imagine an office building.

Some documents are available only inside a specific department.

Some documents are available to the entire company.

Variables work in a very similar way.

JavaScript mainly provides:

  • Global Scope

  • Function Scope

  • Block Scope

Let's understand each one.


Global Scope

A variable declared outside any function or block is considered globally accessible.

Example:

var company = "WhosGeek";

console.log(company);

function showCompany() {
    console.log(company);
}

showCompany();

Output:

WhosGeek
WhosGeek

Here the variable:

company

can be accessed from anywhere in the script.


Real World Example

Imagine a company notice board.

Every employee can read information placed on that board.

Global variables behave similarly.

Every function can access them.


Function Scope

Variables declared using var inside a function are only accessible within that function.

Example:

function test() {

    var score = 100;

    console.log(score);

}

test();

console.log(score);

Output:

100
ReferenceError

Why?

Because score only exists inside the function.

Once the function finishes execution, the variable is no longer accessible outside.


Block Scope

ES6 introduced block-scoped variables using:

let
const

A block means anything inside:

{
}

Example:

{
    let age = 25;
    const city = "Delhi";
}

console.log(age);
console.log(city);

Output:

ReferenceError
ReferenceError

Both variables are only accessible inside their block.


var vs let vs const

This is one of the most common JavaScript interview topics.

Many beginners use them interchangeably.

However, they behave differently.

var

Properties:

  • Function Scoped

  • Can be reassigned

  • Can be redeclared

  • Hoisted with undefined

Example:

var user = "Alex";

var user = "John";

console.log(user);

Output:

John

JavaScript allows redeclaration with var.


let

Properties:

  • Block Scoped

  • Can be reassigned

  • Cannot be redeclared

  • Hoisted but remains in Temporal Dead Zone

Example:

let age = 20;

age = 25;

console.log(age);

Output:

25

const

Properties:

  • Block Scoped

  • Cannot be reassigned

  • Cannot be redeclared

Example:

const PI = 3.14;

PI = 5;

Output:

TypeError

Because constants cannot be reassigned.


A Common Interview Question

What will be the output?

console.log(a);

var a = 10;

Output:

undefined

Why?

JavaScript internally treats it like:

var a;

console.log(a);

a = 10;

This behavior is called:

Hoisting

Hoisting Explained in Simple Words

Imagine a classroom.

Before students enter, the teacher prepares a list of student names.

The names exist before attendance starts.

Similarly, during the creation phase, JavaScript already knows which variables and functions exist.

This process is called hoisting.


Hoisting with var

Example:

console.log(name);

var name = "Devin";

Output:

undefined

The variable exists in memory but has not received a value yet.


Hoisting with let

Example:

console.log(age);

let age = 22;

Output:

ReferenceError

This happens because of the Temporal Dead Zone.


Temporal Dead Zone (TDZ)

This sounds complicated, but the idea is simple.

The Temporal Dead Zone is the time between:

Variable creation

and

Variable initialization

During this period JavaScript knows the variable exists but does not allow access to it.

Example:

console.log(user);

let user = "WhosGeek";

Output:

ReferenceError

Why Did JavaScript Introduce let and const?

Older JavaScript applications relied heavily on var.

This often caused bugs because variables leaked outside blocks.

Example:

if(true){

    var username = "Alex";

}

console.log(username);

Output:

Alex

Even though it was declared inside an if block.

This caused confusion in large applications.

ES6 introduced:

let
const

to solve this problem.


Interactivity in JavaScript

When people say JavaScript makes websites interactive, what does that actually mean?

Imagine a website built only with HTML and CSS.

The page can display content.

But users cannot really interact with it.

JavaScript changes that.

It allows websites to react to user actions.

Examples:

  • Clicking buttons

  • Opening menus

  • Submitting forms

  • Showing notifications

  • Playing animations

  • Creating games

Without JavaScript, modern websites like:

  • Facebook

  • YouTube

  • Netflix

  • Amazon

would feel static.


Real World Example

Suppose a user clicks:

<button>Show Details</button>

JavaScript can respond:

button.addEventListener("click", () => {

    details.style.display = "block";

});

Now the page reacts to user actions.

This is interactivity.


Undefined vs Null

This topic confuses almost every beginner.

Both seem similar.

But they represent different situations.


What is Undefined?

Undefined means:

A variable exists, but no value has been assigned yet.

Example:

let user;

console.log(user);

Output:

undefined

The variable was declared.

No value was assigned.


What is Null?

Null means:

The developer intentionally assigned an empty value.

Example:

let user = null;

console.log(user);

Output:

null

Here the developer is explicitly saying:

This variable currently has no value.

Easy Analogy

Imagine a parking lot.

Undefined:

A parking slot exists,
but nobody assigned a vehicle.

Null:

The parking slot was intentionally marked empty.

Both are empty.

But for different reasons.


Interview Question

console.log(undefined == null);

console.log(undefined === null);

Output:

true
false

Why?

Because:

==

performs type conversion.

Whereas:

===

checks both value and type.


Undeclared vs Undefined Variables

These are different concepts.

Undefined Variable

Declared but no value assigned.

let name;

console.log(name);

Output:

undefined

Undeclared Variable

Never declared at all.

console.log(username);

Output:

ReferenceError

JavaScript cannot find the variable.


Understanding Functions in JavaScript

If variables are the containers of JavaScript, then functions are the workers.

A function is simply a reusable block of code that performs a specific task.

Instead of writing the same code again and again, we place it inside a function and call it whenever we need it.

Imagine working in a restaurant.

Instead of teaching every employee how to cook every dish from scratch, the restaurant creates a standard process.

Whenever someone orders a pizza, the same process is followed.

Functions work in a very similar way.

We define a task once and reuse it multiple times.


Why Do Functions Exist?

Without functions:

let num1 = 10;
let num2 = 20;

console.log(num1 + num2);

let num3 = 30;
let num4 = 40;

console.log(num3 + num4);

We keep repeating logic.

With functions:

function add(a, b){
    return a + b;
}

console.log(add(10,20));
console.log(add(30,40));

Now the code becomes:

  • Cleaner

  • Reusable

  • Easier to maintain


Types of Functions in JavaScript

JavaScript provides several ways to create functions.

The most common ones are:

  • Function Declaration

  • Function Expression

  • Anonymous Function

  • Arrow Function

  • Immediately Invoked Function Expression (IIFE)

  • Generator Function

Let's understand each one.


Function Declaration

A function declaration is the most common way of creating functions.

Example:

function addNumbers(a,b){
    return a + b;
}

console.log(addNumbers(5,10));

Output:

15

Why Are Function Declarations Popular?

Because they are easy to read.

When another developer opens your code, they immediately understand:

function calculateTax(){}
function sendEmail(){}
function createUser(){}

The names explain the purpose.


Function Declarations Are Hoisted

One interesting feature is:

hello();

function hello(){
    console.log("Hello World");
}

Output:

Hello World

The function works even before its declaration appears.

Why?

Because function declarations are hoisted during JavaScript's creation phase.


Function Expressions

A function expression stores a function inside a variable.

Example:

const multiply = function(a,b){
    return a * b;
};

console.log(multiply(2,5));

Output:

10

Difference Between Function Declaration and Function Expression

Function Declaration:

function test(){
}

Function Expression:

const test = function(){
}

The major difference is hoisting.


Interview Question

What happens?

hello();

const hello = function(){
    console.log("Hi");
}

Output:

ReferenceError

Because function expressions are not fully hoisted like function declarations.


Anonymous Functions

Anonymous means:

Without a name

Example:

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

Notice:

No function name exists.

Anonymous functions are commonly used:

  • Inside callbacks

  • Event handlers

  • Array methods

  • Timers


Real World Example

Suppose a user clicks a button.

button.addEventListener("click", function(){

    console.log("Button Clicked");

});

The function only needs to run when the button is clicked.

No need to give it a separate name.

This is why anonymous functions are very common in JavaScript applications.


Immediately Invoked Function Expression (IIFE)

One of the most interesting JavaScript patterns is the IIFE.

Pronounced:

Iffy

An IIFE runs immediately after being created.

Example:

(function(){

    console.log("Executed Immediately");

})();

Output:

Executed Immediately

Why Were IIFEs Popular?

Before:

let
const

developers used IIFEs to create private scope.

Example:

(function(){

    var secret = "hidden";

    console.log(secret);

})();

Outside:

console.log(secret);

Output:

ReferenceError

The variable remains private.


Real World Analogy

Imagine writing notes inside a locked diary.

The notes are available inside the diary.

Nobody outside can access them.

That is how IIFE scope works.


Arrow Functions

Arrow functions were introduced in ES6.

They provide shorter syntax.

Traditional function:

function add(a,b){
    return a+b;
}

Arrow version:

const add = (a,b) => {
    return a+b;
}

Even shorter:

const add = (a,b) => a+b;

Why Developers Love Arrow Functions

Benefits:

  • Short syntax

  • Cleaner code

  • Easy callbacks

  • Common in React and Node.js

Example:

const users = [1,2,3];

users.map(num => num * 2);

Much cleaner than:

users.map(function(num){
    return num * 2;
});

Arrow Function vs Regular Function

This is an extremely common interview topic.

Consider:

const person = {

    name:"Alex",

    greet:function(){

        console.log(this.name);

    }

};

person.greet();

Output:

Alex

Now:

const person = {

    name:"Alex",

    greet:() => {

        console.log(this.name);

    }

};

person.greet();

Output:

undefined

Why?

Arrow functions do not create their own:

this

Instead they borrow:

this

from their surrounding scope.

This is one of the biggest differences between regular functions and arrow functions.


What Are Closures in JavaScript?

Closures are one of the most important concepts in JavaScript.

Unfortunately, they are also one of the most misunderstood.

A closure occurs when:

An inner function remembers variables from its outer function even after the outer function has finished execution.

Sounds complicated.

Let's simplify it.


Real World Analogy

Imagine leaving your office for home.

Before leaving, you put some important notes into your notebook.

Even after leaving the office, you still have access to those notes.

Closures behave similarly.

The outer function finishes execution.

But the inner function still remembers variables from that scope.


Simple Closure Example

function outer(){

    let message = "Hello Developer";

    function inner(){

        console.log(message);

    }

    return inner;

}

const result = outer();

result();

Output:

Hello Developer

What Happened Here?

When:

outer()

finished execution, many beginners assume:

message

should disappear.

However:

inner()

still remembers it.

This remembered environment is called a Closure.


Practical Use Case of Closures

Closures are heavily used for:

  • Data privacy

  • Counters

  • Authentication logic

  • Caching

  • Event handlers

  • React hooks


Counter Example

function createCounter(){

    let count = 0;

    return function(){

        return count++;

    }

}

const counter = createCounter();

console.log(counter());

console.log(counter());

console.log(counter());

Output:

0
1
2

Why Is This Powerful?

Because:

count

cannot be directly modified from outside.

Yet it remembers its value.

This is a perfect example of private state management.


Scope Chain Explained

When JavaScript tries to find a variable, it follows a chain.

Example:

let company = "WhosGeek";

function outer(){

    let department = "Engineering";

    function inner(){

        console.log(company);

        console.log(department);

    }

    inner();

}

outer();

Output:

WhosGeek
Engineering

How JavaScript Searches

JavaScript checks:

  1. Current Scope

  2. Parent Scope

  3. Global Scope

This process is called:

Scope Chain


Understanding String Methods in JavaScript

Strings are one of the most commonly used data types in JavaScript.

Whenever we work with:

  • User names

  • Emails

  • Passwords

  • Search inputs

  • URLs

  • Messages

we are working with strings.

JavaScript provides many built-in methods that make string manipulation easier.

Think of string methods as tools in a toolbox.

Instead of building everything from scratch, JavaScript already gives us ready-made tools.


The trim() Method

One of the most useful string methods is:

trim()

Its job is simple:

Remove extra spaces from the beginning and end of a string.

Example:

let str = "   hello world   ";

console.log(str.length);

Output:

17

Now:

let cleaned = str.trim();

console.log(cleaned.length);

Output:

11

Real World Example

Imagine a user enters:

     alex@gmail.com

with accidental spaces.

Without trim():

"     alex@gmail.com"

The login might fail.

Using trim():

email = email.trim();

removes unnecessary spaces.

This is why trim() is heavily used in forms.


The slice() Method

The slice() method extracts part of a string.

Example:

let text = "JavaScript";

console.log(text.slice(0,4));

Output:

Java

Understanding the Index

J a v a S c r i p t
0 1 2 3 4 5 6 7 8 9

When we write:

text.slice(0,4)

JavaScript starts from:

0

and stops before:

4

Result:

Java

Negative Indexes in slice()

One advantage of slice() is support for negative indexes.

Example:

let text = "JavaScript";

console.log(text.slice(-6));

Output:

Script

This starts counting from the end.


Interview Question

What is the difference between:

slice()

and

substring()

The biggest answer:

slice()

supports negative indexes.

substring()

does not.


The substring() Method

substring() also extracts part of a string.

Example:

let text = "JavaScript";

console.log(text.substring(0,4));

Output:

Java

Interesting Behavior

Example:

console.log("Hello".substring(3,1));

Output:

el

Why?

Because substring automatically swaps the values.

Internally:

substring(1,3)

Negative Values

Example:

console.log("Hello".substring(-2,3));

Output:

Hel

substring treats negative values as:

0

This behavior often appears in interviews.


charAt()

Used to access a character at a specific position.

Example:

let word = "JavaScript";

console.log(word.charAt(4));

Output:

S

indexOf()

Used to find the position of a character or word.

Example:

let text = "Hello World";

console.log(text.indexOf("W"));

Output:

6

Real World Example

Search functionality often uses:

indexOf()

to determine whether text exists inside another string.


Array Methods in JavaScript

Arrays are everywhere.

Examples:

let users = [];

let products = [];

let orders = [];

Most backend APIs return arrays.

Most frontend applications display arrays.

Because of this, array methods are extremely important.


push()

Adds an item to the end of an array.

Example:

let arr = [1,2,3];

arr.push(4);

console.log(arr);

Output:

[1,2,3,4]

pop()

Removes the last element.

Example:

let arr = [1,2,3];

arr.pop();

console.log(arr);

Output:

[1,2]

shift()

Removes the first element.

Example:

let arr = [1,2,3];

arr.shift();

console.log(arr);

Output:

[2,3]

unshift()

Adds an item to the beginning.

Example:

let arr = [2,3];

arr.unshift(1);

console.log(arr);

Output:

[1,2,3]

splice()

One of the most powerful array methods.

Used to:

  • Add elements

  • Remove elements

  • Replace elements

Example:

let arr = [1,2,3,4];

arr.splice(1,2,"new");

console.log(arr);

Output:

[1,"new",4]

Why Developers Love splice()

Suppose we have:

Cart Products

and want to remove an item.

splice() makes that easy.


Difference Between slice() and splice()

This interview question appears frequently.

slice()

Does NOT modify original array

splice()

Modifies original array

Example:

let arr = [1,2,3,4];

let result = arr.slice(1,3);

Output:

result → [2,3]

arr → [1,2,3,4]

Original array remains unchanged.


Higher Order Functions

One of JavaScript's superpowers is:

Higher Order Functions

A Higher Order Function is a function that:

  • Accepts another function as an argument

  • Returns another function

Examples:

map()
filter()
reduce()
find()
forEach()

These methods are used daily in modern JavaScript applications.


map()

The map() method transforms every element of an array.

Example:

let numbers = [1,2,3];

let doubled = numbers.map(num => num * 2);

console.log(doubled);

Output:

[2,4,6]

Real World Example

Suppose we receive products from an API.

products.map(product => ({
    ...product,
    price: product.price * 1.18
}))

We can update all product prices at once.


filter()

Used to return elements matching a condition.

Example:

let numbers = [1,2,3,4,5,6];

let even = numbers.filter(num => num % 2 === 0);

console.log(even);

Output:

[2,4,6]

Real World Example

Filter active users:

users.filter(user => user.active);

Filter completed orders:

orders.filter(order => order.status === "completed");

find()

Returns the first matching element.

Example:

let numbers = [5,12,8,130];

let result = numbers.find(num => num > 10);

console.log(result);

Output:

12

Difference Between find() and filter()

find():

Returns one element

filter():

Returns array

findIndex()

Returns index of first matching element.

Example:

let arr = [1,2,3,4];

let index = arr.findIndex(num => num > 2);

console.log(index);

Output:

2

forEach()

Used when we simply want to loop.

Example:

let users = ["Alex","John","David"];

users.forEach(user => {

    console.log(user);

});

Output:

Alex
John
David

Important Interview Point

forEach() returns:

undefined

Many beginners expect a new array.

It does not create one.


reduce()

One of the most powerful array methods.

reduce() converts an entire array into a single value.

Example:

let numbers = [3,4,5,6];

let total = numbers.reduce((acc,curr)=>{

    return acc + curr;

},0);

console.log(total);

Output:

18

Understanding acc and curr

acc

means:

Accumulator

Stores the running result.

curr

means:

Current Element

Real World Example

Calculate cart total:

cart.reduce((total,item)=>{

    return total + item.price;

},0)

This is extremely common in e-commerce projects.



Understanding NaN in JavaScript

One of the most confusing values in JavaScript is:

NaN

which stands for:

Not a Number

However, the strange part is:

console.log(typeof NaN);

Output:

number

Most beginners see this and think:

"How can Not a Number be a number?"

Let's understand why.


What Exactly Is NaN?

NaN is a special value that represents an invalid mathematical result.

Example:

console.log(Number("hello"));

Output:

NaN

JavaScript tried to convert:

"hello"

into a number.

It failed.

So it returned:

NaN

Real World Analogy

Imagine a calculator.

You type:

apple ÷ banana

The calculator has no idea how to perform that operation.

Instead of crashing, it displays:

Invalid Result

JavaScript's version of that invalid result is:

NaN

A Popular Interview Question

What will be the output?

console.log(NaN === NaN);

Output:

false

Why?

According to JavaScript rules:

NaN

is not equal to anything.

Not even itself.

This is one of JavaScript's famous interview questions.


Correct Way to Check NaN

Instead of:

value === NaN

Use:

Number.isNaN(value);

Example:

console.log(Number.isNaN(NaN));

Output:

true

What Is Type Coercion?

JavaScript is a dynamically typed language.

This means JavaScript automatically converts values from one type to another when needed.

This automatic conversion is called:

Type Coercion

Example 1

console.log("5" + 2);

Output:

52

Why?

JavaScript converts:

2

into:

"2"

Then:

"5" + "2"

becomes:

"52"

Example 2

console.log("5" - 2);

Output:

3

Why?

The subtraction operator only works with numbers.

JavaScript converts:

"5"

into:

5

Then:

5 - 2

becomes:

3

Common Type Coercion Examples

Boolean to Number

console.log(true + 1);

Output:

2

Because:

true = 1

False to Number

console.log(false + 5);

Output:

5

Because:

false = 0

Empty String

console.log("" + 5);

Output:

"5"

String concatenation occurs.


Difference Between == and ===

This is one of the most frequently asked JavaScript interview questions.

Double Equals

==

Performs:

Type Conversion

Example:

console.log(5 == "5");

Output:

true

Because JavaScript converts:

"5"

into:

5

before comparison.


Triple Equals

===

Performs:

Strict Comparison

Example:

console.log(5 === "5");

Output:

false

Because:

Number !== String

Interview Rule

Whenever possible:

Use:

===

instead of:

==

because it avoids unexpected coercion.


What Is Strict Mode?

Strict Mode was introduced in ES5.

It helps developers write safer JavaScript.

Enable it like this:

"use strict";

Why Was Strict Mode Introduced?

Before strict mode:

name = "Alex";

console.log(name);

This works.

JavaScript automatically creates a global variable.

This can create difficult bugs in large applications.


With Strict Mode

"use strict";

name = "Alex";

Output:

ReferenceError

JavaScript now forces us to declare variables properly.


Benefits of Strict Mode

  • Prevents accidental global variables

  • Prevents duplicate parameter names

  • Makes debugging easier

  • Helps write cleaner code


Understanding Map in JavaScript

Before ES6, developers mainly used objects.

Example:

let user = {
    name: "Alex"
};

ES6 introduced:

Map

which stores key-value pairs more efficiently.


Creating a Map

const person = new Map();

Adding Values

person.set("name", "Alex");

person.set("age", 25);

Reading Values

console.log(
    person.get("name")
);

Output:

Alex

Checking Key Existence

console.log(
    person.has("name")
);

Output:

true

Why Use Map Instead of Object?

Map provides:

  • Better performance

  • Any data type as keys

  • Preserves insertion order

  • Built-in utility methods


Example

const map = new Map();

map.set(1, "One");

map.set(true, "Boolean");

map.set({}, "Object");

Objects cannot handle this as elegantly.


Understanding Set

A Set stores:

Unique Values Only

Example

const set = new Set([
    1,
    2,
    3,
    3,
    4,
    4
]);

console.log(set);

Output:

Set(4) {1,2,3,4}

Duplicates are automatically removed.


Real World Example

Suppose we have:

let emails = [
    "alex@gmail.com",
    "alex@gmail.com",
    "john@gmail.com"
];

We can remove duplicates:

let uniqueEmails =
    [...new Set(emails)];

Result:

[
 "alex@gmail.com",
 "john@gmail.com"
]

Map vs Set

FeatureMapSet
Key-Value Pairs
Unique Values
Maintains Order
Duplicate Values

Understanding WeakMap

A WeakMap is similar to Map.

However:

Keys Must Be Objects

Example:

let user = {
    name:"Alex"
};

let weakMap = new WeakMap();

weakMap.set(
    user,
    "Secret Data"
);

Why Does WeakMap Exist?

The biggest reason:

Memory Management

When an object is no longer used:

JavaScript can automatically remove it from memory.

This helps prevent:

Memory Leaks

Real World Analogy

Imagine a visitor pass system.

When visitors leave the building, their temporary passes are automatically destroyed.

WeakMap behaves similarly.

Unused entries disappear automatically.


Understanding WeakSet

WeakSet is similar to Set.

However:

  • Stores objects only

  • Objects are weakly referenced

  • Not iterable

Example:

let user = {
    name:"Alex"
};

let weakSet =
    new WeakSet();

weakSet.add(user);

Why Use WeakSet?

Useful for:

  • Tracking objects

  • Temporary caching

  • Memory-sensitive applications


Interview Question

Can we store numbers inside WeakSet?

Example:

weakSet.add(10);

Output:

TypeError

Because:

WeakSet

only stores objects.


Memory Leak Problem

Suppose an application creates:

10000

objects.

If references remain forever:

Memory usage keeps growing.

WeakMap and WeakSet solve this problem by allowing garbage collection.

This makes them valuable for large-scale applications.


Interview Takeaway

NaN

typeof NaN

returns:

number

Type Coercion

JavaScript automatically converts data types.


Equality Operators

==

allows coercion.

===

does not.


Strict Mode

Helps write safer code.


Map

Stores key-value pairs.


Set

Stores unique values.


WeakMap

Object keys only.

Garbage collection friendly.


WeakSet

Stores object references only.

Great for memory optimization.

These concepts appear repeatedly in JavaScript interviews, React applications, Node.js projects, and large-scale enterprise systems.


Functional Programming in JavaScript

When most beginners start learning JavaScript, they focus on variables, loops, and functions.

As they grow, they discover another programming style called:

Functional Programming (FP)

Functional Programming is a way of writing code where functions become the main building blocks of an application.

Instead of constantly modifying data, we focus on creating small reusable functions.


Simple Definition

Functional Programming is a programming style where:

  • Functions are treated like values

  • Functions can be passed around

  • Functions can return other functions

  • Functions avoid side effects

  • Functions produce predictable outputs


Real World Example

Imagine a factory.

Traditional programming might involve one giant machine doing everything.

Functional Programming is like having:

  • One machine for cutting

  • One machine for painting

  • One machine for packaging

Each machine performs one specific task.

This makes the system easier to maintain.


What Are Pure Functions?

One of the most important ideas in Functional Programming is:

Pure Functions

A pure function:

  • Always returns the same output for the same input

  • Does not modify external data

Example:

function add(a,b){

    return a + b;

}

Input:

add(2,3)

Output:

5

Every time.

No surprises.


Impure Function Example

let total = 0;

function add(value){

    total += value;

    return total;

}

This function depends on external data.

Results may change.

Therefore it is considered impure.


First-Class Functions

One of JavaScript's superpowers is:

Functions Are First-Class Citizens

This means functions can:

  • Be stored in variables

  • Be passed as arguments

  • Be returned from functions

Example:

const greet = function(){

    console.log("Hello");

};

The function is stored inside a variable.


Passing Functions as Arguments

function welcome(name){

    return `Hello ${name}`;

}

function processUser(name, callback){

    return callback(name);

}

console.log(
    processUser(
        "Alex",
        welcome
    )
);

Output:

Hello Alex

Why Is This Useful?

Because it allows flexible and reusable code.

This idea powers:

  • React

  • Node.js

  • Express

  • Array Methods

  • Event Handlers


Higher Order Functions Deep Dive

A Higher Order Function (HOF) is a function that:

  • Accepts another function

  • Returns another function

Example:

map()
filter()
reduce()
find()

All are Higher Order Functions.


Why Are Higher Order Functions Important?

Without HOFs:

for(let i=0;i<arr.length;i++){

}

We repeatedly write loops.

With HOFs:

arr.map()
arr.filter()
arr.reduce()

The logic becomes cleaner and easier to read.


What Is Currying?

Currying is one of those concepts that sounds complicated but is actually simple.

Normally:

function add(a,b,c){

    return a+b+c;

}

Usage:

add(1,2,3);

Curried Version

function curryAdd(a){

    return function(b){

        return function(c){

            return a+b+c;

        }

    }

}

Usage:

curryAdd(1)(2)(3);

Output:

6

Real World Analogy

Imagine ordering food.

Instead of placing the entire order at once:

Pizza
Drink
Dessert

You place it step by step.

JavaScript waits until all required information is available before producing the final result.

Currying works similarly.


Why Use Currying?

Benefits:

  • Function Reusability

  • Cleaner Code

  • Partial Application

  • Functional Programming Patterns

Example:

const add10 = curryAdd(10);

Now:

add10(5)(2);

becomes:

17

Constructor Functions

Before ES6 Classes existed, developers used Constructor Functions.

A Constructor Function is used to create multiple similar objects.

Example:

function Person(name, age){

    this.name = name;

    this.age = age;

}

Creating objects:

const user1 =
    new Person("Alex",25);

const user2 =
    new Person("John",30);

Output:

{
  name:"Alex",
  age:25
}

Why Use Constructor Functions?

Imagine building:

1000 Users

Instead of writing:

let user1 = {};
let user2 = {};
let user3 = {};

We create a blueprint.

The constructor creates objects from that blueprint.


What Is a Prototype?

One of JavaScript's most important concepts is:

Prototype

JavaScript uses:

Prototypal Inheritance

rather than traditional class inheritance.

Every object has access to a prototype.


Example

function Person(name){

    this.name = name;

}

Person.prototype.sayHello =
function(){

    return `Hello ${this.name}`;

};

Now:

const user =
    new Person("Alex");

console.log(
    user.sayHello()
);

Output:

Hello Alex

Why Use Prototype?

Without prototype:

Every object would create its own copy of methods.

With prototype:

Methods are shared.

This saves memory.


Real World Analogy

Imagine a school.

Every student has access to the same rule book.

Instead of giving each student a separate copy, they share one master copy.

That shared copy is similar to a prototype.


Classes in JavaScript

ES6 introduced:

class

Classes make object creation easier and cleaner.

Example:

class Person{

    constructor(name){

        this.name = name;

    }

    greet(){

        return `Hello ${this.name}`;

    }

}

Creating objects:

const user =
    new Person("Alex");

Why Classes Were Introduced

Before classes:

Constructor Functions
+
Prototype

were required.

Classes provide a cleaner syntax.

Internally JavaScript still uses prototypes.

Classes are essentially:

Syntactic Sugar

over prototypes.


Object-Oriented Programming (OOP)

Object-Oriented Programming is a way of organizing software using:

Objects

rather than only functions.


Why OOP Exists

Imagine building:

  • E-commerce

  • Banking Application

  • Social Media App

Thousands of entities exist.

Examples:

User
Product
Order
Payment
Review

OOP helps organize these entities.


The Four Pillars of OOP

The most common interview question:

What are the pillars of OOP?

Answer:

  1. Encapsulation

  2. Abstraction

  3. Inheritance

  4. Polymorphism

Let's understand each one.


Encapsulation

Encapsulation means:

Combining Data and Methods
into one unit.

Example:

class Person{

    constructor(name){

        this.name = name;

    }

    getName(){

        return this.name;

    }

}

Data and behavior stay together.


Real World Example

A medicine capsule contains different ingredients wrapped together.

Similarly:

Data + Functions

are wrapped inside a class.


Abstraction

Abstraction means:

Hide complexity.
Show only necessary details.

Example:

class Car{

    start(){

        this.injectFuel();

        this.ignite();

    }

}

User only calls:

car.start();

They don't need to know the internal engine process.


Real World Example

When driving a car:

You press:

Start Button

You don't need to understand:

  • Fuel Injection

  • Engine Combustion

  • Spark Timing

This is abstraction.


Inheritance

Inheritance allows one class to use properties and methods of another class.

Example:

class Animal{

    eat(){

        console.log("Eating");

    }

}

Child class:

class Dog extends Animal{

}

Now:

const dog =
    new Dog();

dog.eat();

Output:

Eating

Why Use Inheritance?

Avoid code duplication.

Instead of rewriting common functionality:

Reuse Existing Code

Polymorphism

Polymorphism means:

One Method
Many Behaviors

Example:

class Animal{

    sound(){

        console.log("Animal Sound");

    }

}

Child:

class Dog extends Animal{

    sound(){

        console.log("Bark");

    }

}

Another child:

class Cat extends Animal{

    sound(){

        console.log("Meow");

    }

}

Now:

dog.sound();

Output:

Bark

And:

cat.sound();

Output:

Meow

Same method name.

Different behavior.

This is polymorphism.




DOM (Document Object Model)

When a browser loads an HTML page, it doesn't directly work with raw HTML.

Instead, the browser converts the HTML into a structure called:

Document Object Model (DOM)

The DOM represents the webpage as a tree of objects.

Example HTML:

<html>
<body>
<h1>Hello World</h1>
</body>
</html>

Browser creates:

Document
|
html
|
body
|
h1

JavaScript can access and modify these elements dynamically.


Why DOM Exists

Imagine a website where users can:

  • Click buttons
  • Open menus
  • Submit forms
  • Add products to cart

Without the DOM, JavaScript would have no way to interact with webpage elements.


Accessing Elements

const heading =
document.getElementById("title");

Example:

<h1 id="title">
Welcome
</h1>

JavaScript:

const heading =
document.getElementById("title");

heading.innerText =
"Welcome to WhosGeek";

Output:

<h1>
Welcome to WhosGeek
</h1>

The page changes instantly.


Real World Example

Suppose an e-commerce website displays:

Cart Items: 2

When a user adds another product:

cartCount.innerText = 3;

The DOM updates the page without reloading.


Common DOM Methods

getElementById()

document.getElementById("title");

querySelector()

document.querySelector(".card");

Returns first matching element.


querySelectorAll()

document.querySelectorAll(".card");

Returns all matching elements.


createElement()

const div =
document.createElement("div");

Creates a new DOM element.


appendChild()

parent.appendChild(child);

Adds an element to the page.


Event Handling

Websites become interactive through events.

Examples:

  • Click
  • Mouse Hover
  • Keyboard Input
  • Form Submission

Example:

button.addEventListener(
"click",
function(){

alert("Button Clicked");

}
);

Real World Example

When a user clicks:

Add To Cart

An event listener runs.

That event updates:

  • Cart count
  • Price
  • Product list

This is event-driven programming.


BOM (Browser Object Model)

Many beginners confuse:

DOM

and

BOM

They are different.


DOM

Controls:

HTML Elements

Examples:

document.getElementById()
document.querySelector()

BOM

Controls:

Browser Features

Examples:

window
navigator
location
history
screen

window Object

Everything inside the browser exists under:

window

Example:

console.log(window);

The browser prints a massive object.


Alert Box

window.alert(
"Welcome"
);

Usually written as:

alert("Welcome");

Because JavaScript automatically uses window.


Location Object

Provides information about the current URL.

Example:

console.log(
location.href
);

Output:

https://example.com

Redirect User

location.href =
"https://google.com";

Browser navigates to another page.


Navigator Object

Provides browser information.

Example:

console.log(
navigator.userAgent
);

Can reveal:

  • Browser
  • Device
  • Operating System

localStorage

Web applications often need to store data.

Example:

  • Theme settings
  • Login preferences
  • Shopping cart

One solution is:

localStorage

What Is localStorage?

localStorage stores data permanently inside the browser.

Data remains available:

  • After refresh
  • After closing browser
  • After restarting system

Until manually removed.


Store Data

localStorage.setItem(
"username",
"Alex"
);

Read Data

console.log(
localStorage.getItem(
"username"
)
);

Output:

Alex

Remove Data

localStorage.removeItem(
"username"
);

Real World Example

Dark Mode Preference

localStorage.setItem(
"theme",
"dark"
);

When user revisits website:

const theme =
localStorage.getItem(
"theme"
);

Website remembers preference.


sessionStorage

Very similar to localStorage.

Main difference:

Data disappears when tab closes

Store Data

sessionStorage.setItem(
"token",
"123"
);

Read Data

sessionStorage.getItem(
"token"
);

localStorage vs sessionStorage

FeaturelocalStoragesessionStorage
Persists After Browser Restart
Persists After Refresh
Shared Across Tabs
Storage Limit~5MB~5MB

Cookies

Before localStorage existed, websites mainly used cookies.

Cookies are small pieces of data stored by browsers.


Create Cookie

document.cookie =
"name=Alex";

Why Cookies Exist

Common Uses:

  • Authentication
  • User Preferences
  • Session Management

Real World Example

After login:

document.cookie =
"sessionId=abc123";

Server recognizes user on future requests.


Cookies vs localStorage

FeatureCookie                   localStorage
Sent to Server Automatically
Storage SizeSmallLarger
Used For AuthenticationCommonRare
Expiration SupportManual

IndexedDB

Sometimes:

5MB

is not enough.

Applications may need:

  • Offline Data
  • Large Storage
  • Complex Data

This is where IndexedDB helps.


What Is IndexedDB?

IndexedDB is a browser database.

It can store:

  • Objects
  • Files
  • Large datasets

Unlike localStorage:

localStorage

stores strings only.

IndexedDB stores structured data.


Real World Examples

Applications using IndexedDB:

  • Gmail Offline
  • Google Docs Offline
  • Notion
  • Trello

Understanding the JavaScript Event Loop

This is one of the most important JavaScript interview topics.

Many developers memorize answers without understanding the mechanism.

Let's simplify it.


Is JavaScript Single Threaded?

Yes.

JavaScript executes one task at a time.

Think of a restaurant with only one chef.

The chef can cook only one dish at a time.

Similarly:

JavaScript
=
Single Thread

Call Stack

The Call Stack tracks function execution.

Example:

function one(){
two();
}

function two(){
console.log("Hello");
}

one();

Execution:

Call Stack

one()

two()

console.log()

Functions enter stack.

After execution they leave.


The Problem

Suppose:

setTimeout(()=>{
console.log("Hi");
},1000);

JavaScript should not stop everything for 1 second.

Otherwise websites become frozen.


Web APIs

Browser provides:

Web APIs

Examples:

  • setTimeout
  • fetch
  • DOM Events

When JavaScript sees:

setTimeout()

Browser handles timing.

JavaScript continues execution.


Callback Queue

After timer completes:

setTimeout(...)

moves callback into:

Callback Queue

Event Loop

Event Loop constantly checks:

Is Call Stack Empty?

If yes:

Move callback from queue to stack.

This process creates asynchronous behavior.


Visual Flow

Call Stack



Web APIs



Callback Queue



Event Loop



Call Stack

Promises in JavaScript

Before Promises, developers heavily used:

callbacks

This often created:

Callback Hell

Example:

getUser(function(){

getOrders(function(){

getPayment(function(){

});

});

});

Hard to read.

Hard to maintain.


What Is a Promise?

A Promise represents:

Future Result

States:

  • Pending
  • Fulfilled
  • Rejected

Example

const promise =
new Promise(
(resolve,reject)=>{

resolve("Success");

});

Consuming Promise

promise.then(data=>{

console.log(data);

});

Output:

Success

Async Await

ES2017 introduced:

async
await

Making asynchronous code easier.


Promise Version

fetchData()
.then(data=>{

console.log(data);

});

Async Await Version

async function getData(){

const result =
await fetchData();

console.log(result);

}

Much cleaner.

Much easier to read.


Why Developers Prefer Async/Await

Benefits:

  • Cleaner code
  • Better readability
  • Easier debugging
  • Less nesting
  • Better maintenance


Post a Comment

0 Comments