0% found this document useful (0 votes)
39 views64 pages

Essential JavaScript Interview Topics

The document outlines a comprehensive JavaScript interview guide, detailing 30-40 key topics essential for mastering the language. It covers core concepts such as variable declaration, data types, hoisting, scope, closures, and the 'this' keyword, along with practical examples and best practices. The guide aims to prepare candidates for technical interviews by providing in-depth explanations and code snippets for each topic.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
39 views64 pages

Essential JavaScript Interview Topics

The document outlines a comprehensive JavaScript interview guide, detailing 30-40 key topics essential for mastering the language. It covers core concepts such as variable declaration, data types, hoisting, scope, closures, and the 'this' keyword, along with practical examples and best practices. The guide aims to prepare candidates for technical interviews by providing in-depth explanations and code snippets for each topic.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Complete JavaScript Interview Guide: 30-40 Most Important Topics

PART 1: Top 20 Core JavaScript Topics


1. Variable Declaration (var, let, const)

2. Data Types and Type Coercion

3. Hoisting

4. Scope and Scope Chain

5. Closures

6. The 'this' Keyword

7. Prototypes and Prototype Chain

8. Callbacks and Callback Hell

9. Promises

10. Async/Await

11. Event Loop and Call Stack

12. Spread and Rest Operators

13. Destructuring

14. Arrow Functions vs Regular Functions

15. Higher-Order Functions

16. Map, Filter, Reduce

17. Object and Array Methods

18. Classes and OOP in JavaScript

19. Error Handling (try-catch)

20. DOM Manipulation and Events

PART 2: Detailed Explanation of 30 Important Topics

Topic 1: Variable Declaration (var, let, const)


Definition: These are three ways to declare variables in JavaScript. They differ in scope, hoisting behavior, and
reassignment capability.

Key Differences:
Feature var let const

Scope Function-scoped Block-scoped Block-scoped

Hoisting Hoisted & initialized as undefined Hoisted but not initialized Hoisted but not initialized

Reassignment Allowed Allowed Not allowed

Redeclaration Allowed Not allowed Not allowed


 

Code Example:

javascript

// var - function scoped


function varExample() {
if (true) {
var x = 10;
}
[Link](x); // Output: 10 (accessible outside block)
}

// let - block scoped


function letExample() {
if (true) {
let y = 20;
}
[Link](y); // ReferenceError: y is not defined
}

// const - block scoped, cannot be reassigned


const z = 30;
z = 40; // TypeError: Assignment to constant variable

// But const objects can be modified


const obj = { name: 'John' };
[Link] = 'Jane'; // This works
[Link]([Link]); // Output: Jane

// Array elements can be modified even if declared with const


const arr = [1, 2, 3];
[Link](4); // This works
[Link](arr); // Output: [1, 2, 3, 4]

Workflow:

1. JavaScript engine processes variable declaration

2. For var : variable is hoisted and initialized as undefined


3. For let and const : variable is hoisted but not initialized (Temporal Dead Zone)

4. When code reaches variable assignment, value is assigned

Best Practice: Use const by default, let when you need reassignment, avoid var .

Topic 2: Data Types and Type Coercion


Definition: JavaScript has primitive and non-primitive data types. Type coercion is automatic conversion of one
data type to another.

Primitive Types: string , number , boolean , undefined , null , symbol , bigint

Non-Primitive Types: object , array , function

Code Example:

javascript
// Data Types
const str = "Hello"; // string
const num = 42; // number
const bool = true; // boolean
const undef = undefined; // undefined
const nul = null; // null
const sym = Symbol('id'); // symbol
const big = 1000n; // bigint
const obj = { name: 'John' }; // object

// Type Coercion - Implicit Conversion


[Link]("5" + 3); // Output: "53" (string concatenation)
[Link]("5" - 3); // Output: 2 (string to number)
[Link]("5" * "2"); // Output: 10 (both to number)
[Link](true + 1); // Output: 2 (boolean to number)
[Link]("10" == 10); // Output: true (loose equality, type coerced)
[Link]("10" === 10); // Output: false (strict equality, no coercion)

// Falsy Values
[Link](Boolean(0)); // false
[Link](Boolean("")); // false
[Link](Boolean(null)); // false
[Link](Boolean(undefined)); // false
[Link](Boolean(NaN)); // false
[Link](Boolean(false)); // false

// Truthy Values
[Link](Boolean(1)); // true
[Link](Boolean("hello")); // true
[Link](Boolean([])); // true (even empty array)
[Link](Boolean({})); // true (even empty object)

Workflow:

1. When operator used on different types, JavaScript attempts conversion

2. Conversion follows specific rules (addition vs subtraction)

3. Loose equality == allows type coercion

4. Strict equality === does not allow type coercion

Tip: Always use === to avoid unexpected type coercion bugs.


Topic 3: Hoisting

Definition: Hoisting is JavaScript's behavior of moving declarations to the top of their scope before code
execution.

Code Example:

javascript

// Function Hoisting - Functions are fully hoisted


[Link](add(5, 3)); // Output: 8 (works fine)

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

// Variable Hoisting with var


[Link](x); // Output: undefined (not an error)
var x = 5;
[Link](x); // Output: 5

// Variable Hoisting with let/const (Temporal Dead Zone)


[Link](y); // ReferenceError: Cannot access 'y' before initialization
let y = 10;

// Function Expression Hoisting


[Link](multiply(4, 5)); // TypeError: multiply is not a function

var multiply = function(a, b) {


return a * b;
};

// Arrow Function Hoisting


[Link](divide(10, 2)); // TypeError: divide is not a function

const divide = (a, b) => a / b;

What Actually Happens (Behind the Scenes):

javascript
// What you write:
[Link](x);
var x = 5;

// What JavaScript sees:


var x; // Declaration hoisted
[Link](x); // undefined (declared but not assigned)
x = 5; // Assignment stays in place

Workflow:

1. JavaScript parsing phase: declarations are identified and moved to top

2. Variables declared with var are initialized as undefined

3. Variables declared with let / const are in Temporal Dead Zone (TDZ)

4. Execution phase: code runs line by line

5. When TDZ is encountered before assignment, ReferenceError is thrown

Topic 4: Scope and Scope Chain


Definition: Scope determines where variables are accessible. Scope chain is the mechanism JavaScript uses to
find variables.

Types of Scope:

Global Scope

Function Scope

Block Scope

Lexical Scope

Code Example:

javascript
// Global Scope
const globalVar = "I'm global";

function outerFunction() {
// Function Scope (Outer)
const outerVar = "I'm in outer function";

function innerFunction() {
// Function Scope (Inner)
const innerVar = "I'm in inner function";

[Link](innerVar); // Output: I'm in inner function


[Link](outerVar); // Output: I'm in outer function
[Link](globalVar); // Output: I'm global
}

innerFunction();
[Link](innerVar); // ReferenceError: innerVar is not defined
}

outerFunction();

// Block Scope with if statement


if (true) {
let blockVar = "I'm in block";
const blockConst = "Also in block";
}
[Link](blockVar); // ReferenceError

// Scope Chain Example


const a = 1;

function level1() {
const b = 2;

function level2() {
const c = 3;

function level3() {
const d = 4;
[Link](d, c, b, a); // Output: 4 3 2 1
// Scope chain: level3 -> level2 -> level1 -> global
}

level3();
}
level2();
}

level1();

Scope Chain Workflow:

1. JavaScript needs to find variable x

2. Looks in current scope first

3. If not found, looks in parent scope

4. Continues up chain until global scope

5. If not found in global scope, throws ReferenceError

Topic 5: Closures
Definition: A closure is a function that has access to variables from its outer function's scope, even after that
function has returned.

Code Example:

javascript
// Basic Closure
function outer() {
const message = "Hello from outer";

function inner() {
[Link](message); // Access outer's variable
}

return inner;
}

const myClosure = outer();


myClosure(); // Output: Hello from outer

// Practical Closure - Data Privacy


function createCounter() {
let count = 0; // Private variable

return {
increment() {
count++;
return count;
},
decrement() {
count--;
return count;
},
getCount() {
return count;
}
};
}

const counter = createCounter();


[Link]([Link]()); // Output: 1
[Link]([Link]()); // Output: 2
[Link]([Link]()); // Output: 1
[Link]([Link]()); // Output: 1
[Link]([Link]); // Output: undefined (private)

// Closure in Loop
const functions = [];

// Problem: Without closure


for (var i = 0; i < 3; i++) {
[Link](function() {
[Link](i); // All will print 3
});
}

functions[0](); // Output: 3
functions[1](); // Output: 3
functions[2](); // Output: 3

// Solution 1: Using let (creates new scope each iteration)


const functions2 = [];
for (let i = 0; i < 3; i++) {
[Link](function() {
[Link](i);
});
}

functions2[0](); // Output: 0
functions2[1](); // Output: 1
functions2[2](); // Output: 2

// Solution 2: Using closure with IIFE


const functions3 = [];
for (var i = 0; i < 3; i++) {
[Link]((function(j) {
return function() {
[Link](j);
};
})(i));
}

functions3[0](); // Output: 0
functions3[1](); // Output: 1
functions3[2](); // Output: 2

Why Closures Matter:

1. Data encapsulation and privacy

2. Function factories

3. Callbacks and event handlers

4. Module pattern

Topic 6: The 'this' Keyword


Definition: this refers to the object that is executing the current code. Its value depends on how the function is
called.

Code Example:

javascript
// 1. Method Call - 'this' refers to the object
const obj = {
name: "John",
greet() {
[Link](`Hello, ${[Link]}`);
}
};

[Link](); // Output: Hello, John

// 2. Function Call - 'this' refers to global object (in non-strict mode)


function sayName() {
[Link]([Link]);
}

sayName(); // Output: undefined (this is global object)

// 3. Constructor - 'this' refers to new instance


function Person(name) {
[Link] = name;
}

const person = new Person("Alice");


[Link]([Link]); // Output: Alice

// 4. Arrow Function - 'this' is inherited from enclosing scope


const person2 = {
name: "Bob",
greet() {
const arrowFunc = () => {
[Link]([Link]); // 'this' from greet method
};
arrowFunc();
}
};

[Link](); // Output: Bob

// 5. Explicit Binding with call, apply, bind


function introduce(greeting) {
[Link](`${greeting}, I'm ${[Link]}`);
}

const user = { name: "Charlie" };

[Link](user, "Hi"); // Output: Hi, I'm Charlie


[Link](user, ["Hello"]); // Output: Hello, I'm Charlie

const boundFunc = [Link](user);


boundFunc("Hey"); // Output: Hey, I'm Charlie

this Binding Rules (In Order of Priority):

1. new keyword - points to new instance

2. call , apply , bind - explicit binding

3. Method call - points to the object

4. Function call - points to global object

5. Arrow functions - lexical this (from parent scope)

Topic 7: Prototypes and Prototype Chain


Definition: Every JavaScript object has a prototype. Prototype chain is how JavaScript objects inherit
properties and methods.

Code Example:

javascript
// Object Prototype
const person = {
name: "John",
greet() {
[Link](`Hello, I'm ${[Link]}`);
}
};

// Accessing prototype
[Link]([Link](person));
[Link](person.__proto__); // Deprecated but still works

// Constructor Function and Prototype


function Animal(name) {
[Link] = name;
}

[Link] = function() {
[Link](`${[Link]} makes a sound`);
};

const dog = new Animal("Dog");


[Link](); // Output: Dog makes a sound

// Prototype Chain
[Link]([Link]('name')); // true (own property)
[Link]([Link]('speak')); // false (inherited from prototype)
[Link]('speak' in dog); // true (includes prototype)

// Prototype Chain Lookup


function Vehicle(type) {
[Link] = type;
}

[Link] = function() {
[Link](`${[Link]} started`);
};

function Car(type, doors) {


[Link](this, type);
[Link] = doors;
}

// Set up inheritance
[Link] = [Link]([Link]);
[Link] = Car;
[Link] = function() {
[Link](`${[Link]} is driving`);
};

const myCar = new Car("Toyota", 4);


[Link](); // Output: Toyota started (from [Link])
[Link](); // Output: Toyota is driving (from [Link])

// Prototype Chain: myCar -> [Link] -> [Link] -> [Link] -> null

Prototype Chain Lookup Workflow:

1. Check if property exists on object itself

2. Check object's prototype

3. Check prototype's prototype

4. Continue up the chain until [Link]

5. If not found, return undefined

Topic 8: Callbacks and Callback Hell


Definition: A callback is a function passed as an argument to another function. It executes after some operation
is completed.

Code Example:

javascript
// Simple Callback
function greet(name, callback) {
[Link](`Hello, ${name}`);
callback();
}

function sayGoodbye() {
[Link]("Goodbye!");
}

greet("John", sayGoodbye);
// Output: Hello, John
// Output: Goodbye!

// Practical Callback - Simulating API Call


function fetchUser(id, callback) {
[Link](`Fetching user ${id}...`);

setTimeout(() => {
const user = { id: id, name: "John Doe" };
callback(user);
}, 1000);
}

function displayUser(user) {
[Link](`User: ${[Link]}`);
}

fetchUser(1, displayUser);
// Output (after 1 second): User: John Doe

// Callback Hell (Pyramid of Doom) - AVOID THIS


function fetchUserData(id, callback) {
setTimeout(() => {
const user = { id: id, name: "John" };
callback(user);
}, 500);
}

function fetchUserPosts(userId, callback) {


setTimeout(() => {
const posts = [{ id: 1, title: "Post 1" }];
callback(posts);
}, 500);
}
function fetchPostComments(postId, callback) {
setTimeout(() => {
const comments = [{ id: 1, text: "Great post!" }];
callback(comments);
}, 500);
}

// Callback Hell - Difficult to read


fetchUserData(1, function(user) {
[Link]("User:", [Link]);

fetchUserPosts([Link], function(posts) {
[Link]("Posts:", [Link]);

fetchPostComments(posts[0].id, function(comments) {
[Link]("Comments:", [Link]);
});
});
});

// Why Callbacks Are Necessary


const button = [Link]('button');
[Link]('click', function() {
[Link]('Button clicked!'); // Callback function
});

Why Use Callbacks:

1. Asynchronous operations (API calls, timers)

2. Event handling

3. Array methods (forEach, map, filter)

4. Deferred execution

Problems with Callbacks:

1. Callback Hell - deep nesting

2. Difficult error handling

3. Hard to read and maintain

4. Easy to make mistakes


Topic 9: Promises

Definition: A Promise is an object that represents the eventual completion (or failure) of an asynchronous
operation and its resulting value.

States of Promise: pending, fulfilled, rejected

Code Example:

javascript
// Creating a Promise
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve("Operation successful!");
} else {
reject("Operation failed!");
}
}, 1000);
});

// Consuming a Promise
myPromise
.then(result => {
[Link](result); // Output: Operation successful!
})
.catch(error => {
[Link](error);
});

// Promise Chain - Better than callback hell


function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({ id: id, name: "John" });
} else {
reject("Invalid ID");
}
}, 500);
});
}

function fetchPosts(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([{ id: 1, title: "Post 1" }]);
}, 500);
});
}

// Much cleaner than callback hell


fetchUser(1)
.then(user => {
[Link]("User:", [Link]);
return fetchPosts([Link]);
})
.then(posts => {
[Link]("Posts:", [Link]);
})
.catch(error => {
[Link]("Error:", error);
})
.finally(() => {
[Link]("Operation completed");
});

// [Link] - Wait for all promises


const promise1 = [Link](3);
const promise2 = new Promise(resolve => setTimeout(() => resolve('foo'), 100));
const promise3 = fetch('[Link] => 'fetch failed');

[Link]([promise1, promise2, promise3])


.then(values => {
[Link]("All promises resolved:", values);
});

// [Link] - First to complete wins


[Link]([promise1, promise2, promise3])
.then(value => {
[Link]("First promise resolved:", value);
});

Promise Workflow:

1. Promise created in pending state

2. resolve() called -> Promise becomes fulfilled

3. reject() called -> Promise becomes rejected

4. .then() executes on fulfillment

5. .catch() executes on rejection

6. .finally() executes regardless of outcome

Topic 10: Async/Await


Definition: Async/await is syntactic sugar over Promises that makes asynchronous code look synchronous and
easier to read.

Code Example:
javascript
// Basic Async/Await
async function fetchData() {
[Link]("Fetching data...");

// The function returns a Promise


return "Data fetched";
}

// Calling async function


fetchData().then(result => {
[Link](result); // Output: Data fetched
});

// Async/Await with Real Async Operations


async function getUserData(id) {
try {
[Link]("Fetching user...");

// Await pauses execution until Promise resolves


const response = await fetch(`[Link]
const user = await [Link]();

[Link]("Fetching posts...");
const postsResponse = await fetch(`[Link]
const posts = await [Link]();

return { user, posts };


} catch (error) {
[Link]("Error:", error);
} finally {
[Link]("Operation completed");
}
}

// Calling the async function


getUserData(1).then(data => {
[Link](data);
});

// Simulated Async Function


function simulateAPICall(value, delay) {
return new Promise(resolve => {
setTimeout(() => {
resolve(value);
}, delay);
});
}

// Using Async/Await
async function demonstrateAwait() {
[Link]("Start");

const result1 = await simulateAPICall("First", 1000);


[Link](result1); // Output: First (after 1 second)

const result2 = await simulateAPICall("Second", 1000);


[Link](result2); // Output: Second (after 1 more second)

[Link]("End");
// Total time: 2 seconds (sequential)
}

demonstrateAwait();

// Parallel Execution with Async/Await


async function parallelExecution() {
[Link]("Start");

// Both run simultaneously


const [result1, result2] = await [Link]([
simulateAPICall("First", 1000),
simulateAPICall("Second", 1000)
]);

[Link](result1, result2);
// Total time: 1 second (parallel)
}

parallelExecution();

// Error Handling in Async/Await


async function withErrorHandling() {
try {
const result = await simulateAPICall("Data", 500);
[Link]("Result:", result);
} catch (error) {
[Link]("Caught error:", error);
}
}

withErrorHandling();
Async/Await Workflow:

1. async keyword makes function return Promise

2. await pauses execution until Promise settles

3. Control returns to caller immediately

4. When Promise resolves, execution resumes

5. try/catch handles errors

6. finally block executes regardless

Advantages over Promises:

1. Looks synchronous, easier to understand

2. Better error handling with try/catch

3. Easier debugging (better stack traces)

4. Cleaner code

Topic 11: Event Loop and Call Stack


Definition: Event Loop manages asynchronous operations. Call Stack executes functions. Message Queue
holds callbacks.

Components:

Call Stack: where code executes

Web APIs: browser's APIs (setTimeout, fetch, etc.)

Message Queue: callbacks waiting to execute

Event Loop: monitors stack and queue

Code Example:

javascript
// Understanding Call Stack and Event Loop
[Link]("1. Start");

setTimeout(() => {
[Link]("2. Timeout callback");
}, 0); // Even 0ms goes to queue

[Link]()
.then(() => {
[Link]("3. Promise callback");
});

[Link]("4. End");

// Output:
// 1. Start
// 4. End
// 3. Promise callback (Microtask queue - higher priority)
// 2. Timeout callback (Macrotask queue - lower priority)

// Detailed Explanation
/*
CALL STACK (synchronous):
- [Link]("1. Start") executes immediately
- setTimeout registered in Web APIs
- Promise registered in Microtask Queue
- [Link]("4. End") executes immediately

EVENT LOOP:
- Call Stack is empty
- Checks Microtask Queue (Promises, MutationObserver)
- Executes all microtasks
- Then checks Macrotask Queue (setTimeout, setInterval, I/O)
- Executes one macrotask
- Repeats
*/

// Microtask vs Macrotask Queue


[Link]("Script start");

setTimeout(() => {
[Link]("setTimeout 1");
[Link]().then(() => [Link]("Promise inside setTimeout"));
}, 0);

[Link]()
.then(() => {
[Link]("Promise 1");
setTimeout(() => [Link]("setTimeout inside Promise"), 0);
})
.then(() => {
[Link]("Promise 2");
});

[Link]("Script end");

// Output:
// Script start
// Script end
// Promise 1
// Promise 2
// setTimeout 1
// Promise inside setTimeout
// setTimeout inside Promise

// Visual Flow:
/*
1. Synchronous code runs: "Script start", "Script end"
2. All Microtasks execute: "Promise 1", "Promise 2"
3. One Macrotask: "setTimeout 1"
4. Microtasks again: "Promise inside setTimeout"
5. Next Macrotask: "setTimeout inside Promise"
*/

Event Loop Priority:

1. Call Stack: All synchronous code

2. Microtask Queue: Promises, async/await, MutationObserver, queueMicrotask

3. Macrotask Queue: setTimeout, setInterval, setImmediate, I/O operations

Topic 12: Spread and Rest Operators


Definition: Spread operator ( ... ) expands arrays/objects. Rest operator ( ... ) collects values into array/object.

Code Example:

javascript
// Spread Operator - Arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const combined = [...arr1, ...arr2];


[Link](combined); // Output: [1, 2, 3, 4, 5, 6]

// Spread Operator - Copying


const original = [1, 2, 3];
const copy = [...original];
[Link](4);

[Link](original); // Output: [1, 2, 3] (unchanged)


[Link](copy); // Output: [1, 2, 3, 4]

// Spread Operator - Objects


const obj1 = { name: "John", age: 30 };
const obj2 = { city: "New York" };

const merged = { ...obj1, ...obj2 };


[Link](merged); // Output: { name: 'John', age: 30, city: 'New York' }

// Spread Operator - Overriding properties


const updated = { ...obj1, age: 31 };
[Link](updated); // Output: { name: 'John', age: 31 }

// Rest Operator - Function Parameters


function sum(...numbers) {
return [Link]((total, num) => total + num, 0);
}

[Link](sum(1, 2, 3, 4, 5)); // Output: 15

// Rest Operator - Capturing remaining parameters


function logInfo(name, age, ...hobbies) {
[Link](`${name} is ${age} years old`);
[Link]("Hobbies:", hobbies);
}

logInfo("John", 30, "reading", "gaming", "sports");


// Output:
// John is 30 years old
// Hobbies: ['reading', 'gaming', 'sports']

// Rest Operator - Destructuring


const [first, second, ...rest] = [1, 2, 3, 4, 5];
[Link](first); // Output: 1
[Link](second); // Output: 2
[Link](rest); // Output: [3, 4, 5]

// Rest with Objects


const { name, ...others } = { name: "John", age: 30, city: "NY" };
[Link](name); // Output: John
[Link](others); // Output: { age: 30, city: 'NY' }

Key Difference:

Spread: Expands/unpacks arrays/objects

Rest: Collects/packs values into array/object

Topic 13: Destructuring


Definition: Destructuring extracts values from arrays or properties from objects into distinct variables.

Code Example:

javascript
// Array Destructuring
const colors = ["red", "green", "blue"];
const [primary, secondary, tertiary] = colors;

[Link](primary); // Output: red


[Link](secondary); // Output: green

// Skip elements
const [first, , third] = colors;
[Link](first, third); // Output: red blue

// Default values
const [a, b, c = "yellow"] = ["red", "green"];
[Link](c); // Output: yellow

// Object Destructuring
const person = { name: "John", age: 30, city: "New York" };
const { name, age } = person;

[Link](name); // Output: John


[Link](age); // Output: 30

// Rename variables
const { name: personName, age: personAge } = person;
[Link](personName); // Output: John

// Default values
const { name, country = "USA" } = person;
[Link](country); // Output: USA

// Nested Destructuring
const user = {
id: 1,
profile: {
name: "Alice",
address: {
city: "New York",
zip: "10001"
}
}
};

const { profile: { address: { city } } } = user;


[Link](city); // Output: New York

// Function Parameter Destructuring


function displayUser({ name, age, city = "Unknown" }) {
[Link](`${name} is ${age} years old from ${city}`);
}

displayUser({ name: "Bob", age: 25, city: "Boston" });


// Output: Bob is 25 years old from Boston

// Array in Function Parameters


function logCoordinates([x, y]) {
[Link](`Point: (${x}, ${y})`);
}

logCoordinates([10, 20]); // Output: Point: (10, 20)

Benefits:

1. Cleaner, more readable code

2. Reduces variable assignment statements

3. Easy extraction of nested values

4. Works great with function parameters

Topic 14: Arrow Functions vs Regular Functions


Definition: Arrow functions are a concise syntax for regular functions with different this binding.

Code Example:

javascript
// Regular Function
function regularAdd(a, b) {
return a + b;
}

[Link](regularAdd(5, 3)); // Output: 8

// Arrow Function - Equivalent


const arrowAdd = (a, b) => a + b;
[Link](arrowAdd(5, 3)); // Output: 8

// Arrow Function Syntax Variations


const square = x => x * x; // Single parameter, no parentheses
const greet = () => "Hello"; // No parameters
const multiply = (a, b) => {
const result = a * b;
return result;
}; // Multiple statements need braces

// Key Difference: 'this' Binding


const person = {
name: "John",

// Regular function - 'this' is the object


greetRegular: function() {
[Link](`Regular: Hello, ${[Link]}`);
},

// Arrow function - 'this' is from parent scope (global/window)


greetArrow: () => {
[Link](`Arrow: Hello, ${[Link]}`);
}
};

[Link](); // Output: Regular: Hello, John


[Link](); // Output: Arrow: Hello, undefined

// Practical Example: Event Handler


const button = {
name: "MyButton",

// Regular function - 'this' is the button object


setupRegular: function() {
[Link]('click', function() {
[Link]([Link]); // 'this' is the event target
});
},

// Arrow function - 'this' is preserved from setupArrow


setupArrow: function() {
[Link]('click', () => {
[Link]([Link]); // 'this' is the button object
});
}
};

// Arguments Object
function regularFunc(a, b) {
[Link](arguments); // Works - array-like object
}

const arrowFunc = (a, b) => {


[Link](arguments); // ReferenceError - no arguments object
};

regularFunc(1, 2); // Output: [1, 2]

// Use Rest Operator with Arrow Functions


const arrowWithRest = (...args) => {
[Link](args); // Output: [1, 2, 3]
};

arrowWithRest(1, 2, 3);

// Cannot use Arrow Functions as Constructors


const regularConstructor = function(name) {
[Link] = name;
};

const obj = new regularConstructor("John");


[Link]([Link]); // Output: John

// This will throw error


const arrowConstructor = (name) => {
[Link] = name;
};

// new arrowConstructor("John"); // TypeError: arrowConstructor is not a constructor

Comparison Table:
Feature Regular Function Arrow Function

this binding Dynamic (call-site) Lexical (parent scope)

arguments object Available Not available

Constructor Can be used Cannot be used

Syntax Verbose Concise

prototype property Has it No prototype property


 

Topic 15: Higher-Order Functions


Definition: A higher-order function is a function that takes another function as an argument or returns a
function.

Code Example:

javascript
// Function that takes another function as argument
function processNumbers(numbers, operation) {
return [Link](operation);
}

const double = num => num * 2;


const result = processNumbers([1, 2, 3], double);
[Link](result); // Output: [2, 4, 6]

// Function that returns another function


function multiplier(factor) {
return function(number) {
return number * factor;
};
}

const double2 = multiplier(2);


const triple = multiplier(3);

[Link](double2(5)); // Output: 10
[Link](triple(5)); // Output: 15

// Function Composition
function compose(f, g) {
return function(x) {
return f(g(x));
};
}

const add = x => x + 2;


const multiply = x => x * 3;

const composed = compose(add, multiply);


[Link](composed(5)); // Output: 17 (first multiply: 5*3=15, then add: 15+2=17)

// Currying - Higher-Order Function Pattern


function curry(fn) {
return function curried(...args) {
if ([Link] >= [Link]) {
return [Link](this, args);
} else {
return function(...nextArgs) {
return curried(...args, ...nextArgs);
};
}
};
}

function add3Numbers(a, b, c) {
return a + b + c;
}

const curriedAdd = curry(add3Numbers);


[Link](curriedAdd(1)(2)(3)); // Output: 6
[Link](curriedAdd(1, 2)(3)); // Output: 6

// Practical Example: Middleware Pattern


function logRequest(fn) {
return function(...args) {
[Link](`Calling function with args:`, args);
return fn(...args);
};
}

function apiCall(endpoint) {
return `Response from ${endpoint}`;
}

const apiWithLog = logRequest(apiCall);


[Link](apiWithLog('/users'));
// Output: Calling function with args: ['/users']
// Output: Response from /users

Topic 16: Map, Filter, Reduce


Definition: Array methods for functional programming. Map transforms, filter selects, reduce aggregates.

Code Example:

javascript
const numbers = [1, 2, 3, 4, 5];

// MAP - Transform each element


const doubled = [Link](num => num * 2);
[Link](doubled); // Output: [2, 4, 6, 8, 10]

// MAP with objects


const users = [
{ name: "John", age: 30 },
{ name: "Jane", age: 25 }
];

const names = [Link](user => [Link]);


[Link](names); // Output: ['John', 'Jane']

// FILTER - Select elements matching condition


const evenNumbers = [Link](num => num % 2 === 0);
[Link](evenNumbers); // Output: [2, 4]

// FILTER with objects


const adults = [Link](user => [Link] >= 30);
[Link](adults); // Output: [{ name: 'John', age: 30 }]

// REDUCE - Aggregate into single value


const sum = [Link]((total, num) => total + num, 0);
[Link](sum); // Output: 15

// REDUCE - Product
const product = [Link]((acc, num) => acc * num, 1);
[Link](product); // Output: 120

// REDUCE - Create object from array


const userMap = [Link]((acc, user) => {
acc[[Link]] = [Link];
return acc;
}, {});
[Link](userMap); // Output: { John: 30, Jane: 25 }

// REDUCE - Flatten array


const nested = [[1, 2], [3, 4], [5, 6]];
const flat = [Link]((acc, arr) => [Link](arr), []);
[Link](flat); // Output: [1, 2, 3, 4, 5, 6]

// Combining Map, Filter, Reduce


const complexResult = numbers
.filter(num => num > 2) // [3, 4, 5]
.map(num => num * 2) // [6, 8, 10]
.reduce((sum, num) => sum + num, 0); // 24

[Link](complexResult); // Output: 24

// REDUCE with index and full array


const average = [Link]((sum, num, index, array) => {
const newSum = sum + num;
if (index === [Link] - 1) {
return newSum / [Link];
}
return newSum;
}, 0);

[Link](average); // Output: 3

Topic 17: Object and Array Methods


Definition: Built-in methods for manipulating objects and arrays efficiently.

Code Example:

javascript
// OBJECT METHODS

// [Link] - Get all keys


const obj = { name: "John", age: 30, city: "NY" };
[Link]([Link](obj)); // Output: ['name', 'age', 'city']

// [Link] - Get all values


[Link]([Link](obj)); // Output: ['John', 30, 'NY']

// [Link] - Get key-value pairs


[Link]([Link](obj));
// Output: [['name', 'John'], ['age', 30], ['city', 'NY']]

// [Link] - Copy/merge objects


const target = { a: 1 };
const source = { b: 2, c: 3 };
const result = [Link](target, source);
[Link](result); // Output: { a: 1, b: 2, c: 3 }

// [Link] - Make immutable


const frozen = [Link]({ x: 10 });
frozen.x = 20; // Silently fails in non-strict mode
[Link](frozen.x); // Output: 10

// [Link] - Allow modification, prevent adding/deleting


const sealed = [Link]({ x: 10 });
sealed.x = 20; // Works
sealed.y = 30; // Fails
[Link](sealed); // Output: { x: 20 }

// [Link] - Create with specific prototype


const proto = { greet() { return "Hello"; } };
const newObj = [Link](proto);
[Link]([Link]()); // Output: Hello

// ARRAY METHODS

const arr = [1, 2, 3, 4, 5];

// find - First matching element


const first = [Link](num => num > 3);
[Link](first); // Output: 4

// findIndex - Index of first match


const index = [Link](num => num > 3);
[Link](index); // Output: 3
// some - Check if any matches
const hasEven = [Link](num => num % 2 === 0);
[Link](hasEven); // Output: true

// every - Check if all match


const allPositive = [Link](num => num > 0);
[Link](allPositive); // Output: true

// includes - Check if contains


[Link]([Link](3)); // Output: true

// indexOf - Position of element


[Link]([Link](3)); // Output: 2

// slice - Get portion (non-mutating)


[Link]([Link](1, 3)); // Output: [2, 3]

// splice - Remove/add elements (mutating)


const arr2 = [1, 2, 3, 4, 5];
[Link](1, 2, 'a', 'b');
[Link](arr2); // Output: [1, 'a', 'b', 4, 5]

// concat - Combine arrays


const arr3 = [1, 2].concat([3, 4]);
[Link](arr3); // Output: [1, 2, 3, 4]

// reverse - Reverse array (mutating)


const arr4 = [1, 2, 3];
[Link]();
[Link](arr4); // Output: [3, 2, 1]

// sort - Sort elements


const unsorted = [3, 1, 4, 1, 5];
[Link]((a, b) => a - b);
[Link](unsorted); // Output: [1, 1, 3, 4, 5]

// join - Convert to string


[Link]([Link]('-')); // Output: 1-2-3-4-5

// flat - Flatten nested array


const nested = [1, [2, [3, 4]]];
[Link]([Link]()); // Output: [1, 2, [3, 4]]
[Link]([Link](2)); // Output: [1, 2, 3, 4]

// flatMap - Map then flatten


const words = ['hello', 'world'];
const chars = [Link](word => [Link](''));
[Link](chars); // Output: ['h','e','l','l','o','w','o','r','l','d']

Topic 18: Classes and OOP in JavaScript


Definition: Classes provide a way to structure code with inheritance, encapsulation, and polymorphism.

Code Example:

javascript
// Basic Class
class Animal {
constructor(name) {
[Link] = name;
}

speak() {
[Link](`${[Link]} makes a sound`);
}
}

const dog = new Animal("Dog");


[Link](); // Output: Dog makes a sound

// Inheritance
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call parent constructor
[Link] = breed;
}

speak() {
[Link](`${[Link]} barks`);
}

getBreed() {
[Link](`${[Link]} is a ${[Link]}`);
}
}

const myDog = new Dog("Rex", "German Shepherd");


[Link](); // Output: Rex barks
[Link](); // Output: Rex is a German Shepherd

// Static Methods
class MathUtils {
static add(a, b) {
return a + b;
}

static multiply(a, b) {
return a * b;
}
}

[Link]([Link](5, 3)); // Output: 8


// Static methods don't need instance

// Getters and Setters


class Person {
constructor(name, age) {
this._age = age; // Convention: _ for private
[Link] = name;
}

get age() {
return this._age;
}

set age(newAge) {
if (newAge < 0) {
[Link]("Age cannot be negative");
} else {
this._age = newAge;
}
}
}

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


[Link]([Link]); // Output: 30
[Link] = 31;
[Link]([Link]); // Output: 31
[Link] = -5; // Output: Age cannot be negative

// Private Fields (Modern JavaScript)


class BankAccount {
#balance = 0; // Private field

constructor(initialBalance) {
this.#balance = initialBalance;
}

deposit(amount) {
this.#balance += amount;
}

getBalance() {
return this.#balance;
}
}

const account = new BankAccount(1000);


[Link](500);
[Link]([Link]()); // Output: 1500
// [Link](account.#balance); // SyntaxError - cannot access private field

// Method Chaining
class Calculator {
constructor(value = 0) {
[Link] = value;
}

add(num) {
[Link] += num;
return this; // Return this for chaining
}

subtract(num) {
[Link] -= num;
return this;
}

multiply(num) {
[Link] *= num;
return this;
}

getResult() {
return [Link];
}
}

const calc = new Calculator(10);


const result = [Link](5).multiply(2).subtract(3).getResult();
[Link](result); // Output: 27 (10+5=15, 15*2=30, 30-3=27)

Topic 19: Error Handling (try-catch)


Definition: Try-catch helps handle runtime errors without crashing the program.

Code Example:

javascript
// Basic Try-Catch
try {
const result = riskyFunction();
[Link](result);
} catch (error) {
[Link]("Error caught:", [Link]);
}

function riskyFunction() {
throw new Error("Something went wrong!");
}

// Try-Catch-Finally
try {
[Link]("Attempting operation");
throw new Error("Operation failed");
} catch (error) {
[Link]("Error:", [Link]);
} finally {
[Link]("Cleanup code runs regardless");
}

// Output:
// Attempting operation
// Error: Operation failed
// Cleanup code runs regardless

// Custom Error Types


class ValidationError extends Error {
constructor(message) {
super(message);
[Link] = "ValidationError";
}
}

function validateAge(age) {
if (age < 0 || age > 150) {
throw new ValidationError("Invalid age");
}
return `Valid age: ${age}`;
}

try {
[Link](validateAge(-5));
} catch (error) {
if (error instanceof ValidationError) {
[Link]("Validation failed:", [Link]);
} else {
[Link]("Unexpected error:", [Link]);
}
}

// Error Handling with Async/Await


async function fetchUserData(userId) {
try {
const response = await fetch(`/api/user/${userId}`);

if (![Link]) {
throw new Error(`HTTP Error: ${[Link]}`);
}

const data = await [Link]();


return data;
} catch (error) {
[Link]("Failed to fetch:", [Link]);
// Could also re-throw: throw error;
} finally {
[Link]("Request completed");
}
}

// Error Handling with Promises


function fetchData(url) {
return fetch(url)
.then(response => {
if (![Link]) {
throw new Error(`HTTP ${[Link]}`);
}
return [Link]();
})
.catch(error => {
[Link]("Fetch failed:", [Link]);
return null;
});
}

// Stack Traces
try {
function outer() {
inner();
}

function inner() {
throw new Error("Error in inner function");
}

outer();
} catch (error) {
[Link]([Link]);
// Shows: Error in inner function
// at inner
// at outer
// at <anonymous>
}

Topic 20: DOM Manipulation and Events


Definition: DOM (Document Object Model) represents HTML. Events trigger when user interacts with page.

Code Example:

javascript
// SELECTING ELEMENTS

// Single element
const element = [Link]('myId');
const div = [Link]('.myClass');

// Multiple elements
const paragraphs = [Link]('p');
const divs = [Link]('myClass');

// MODIFYING ELEMENTS

[Link] = "New text"; // Set text


[Link] = "<p>HTML content</p>"; // Set HTML

[Link] = "red"; // Inline styles


[Link]('active'); // Add class
[Link]('inactive'); // Remove class
[Link]('visible'); // Toggle class

// CREATING ELEMENTS

const newDiv = [Link]('div');


[Link] = "New element";
[Link] = "new-class";
[Link](newDiv);

// EVENTS

// Click Event
const button = [Link]('button');
[Link]('click', function(event) {
[Link]('Button clicked');
[Link]([Link]); // The element that triggered event
});

// Multiple Events
const input = [Link]('input');

[Link]('focus', () => {
[Link]('Input focused');
});

[Link]('blur', () => {
[Link]('Input lost focus');
});
[Link]('input', (e) => {
[Link]('Current value:', [Link]);
});

// Event Delegation - Efficient for many elements


const list = [Link]('ul');
[Link]('click', (e) => {
if ([Link] === 'LI') {
[Link]('Clicked:', [Link]);
}
});

// Event Flow - Bubbling


[Link]('click', (e) => {
[Link]('Document clicked');
}, false); // false = bubbling phase (default)

// Event Flow - Capturing


[Link]('click', (e) => {
[Link]('Document clicked (capture)');
}, true); // true = capturing phase

// Stop Propagation
[Link]('click', (e) => {
[Link](); // Prevent bubbling
[Link]('Button clicked - stops here');
});

// Prevent Default
const form = [Link]('form');
[Link]('submit', (e) => {
[Link](); // Prevent page reload
[Link]('Form submission prevented');
});

// Remove Event Listener


function handleClick() {
[Link]('Clicked');
}

[Link]('click', handleClick);
[Link]('click', handleClick);

// Event Object Properties


[Link]('keydown', (e) => {
[Link]('Key:', [Link]);
[Link]('Code:', [Link]);
[Link]('Ctrl pressed:', [Link]);
[Link]('Alt pressed:', [Link]);
});

PART 3: Comparative Questions (Why JavaScript, Why Not Python, etc.)

1. Why JavaScript and Not Python?


JavaScript:

Runs natively in browsers (frontend development)

Single language for both frontend and backend ([Link])

Async-first design (perfect for web)

Fast development with hot reloading

Large ecosystem (npm packages)

Python:

Simpler syntax, easier to learn

Better for data science and AI

Not ideal for browser execution

Slower than JavaScript for web

When to use what:

JavaScript: Web applications, real-time updates, SPAs

Python: Data analysis, machine learning, backend services

2. Why Use Async/Await Instead of Callbacks?


Callbacks (Old Way):

javascript
function getUserAndPosts(userId, callback) {
getUser(userId, function(user) {
getPosts([Link], function(posts) {
callback(user, posts);
});
});
}

getUserAndPosts(1, function(user, posts) {


[Link](user, posts);
});
// Hard to read, error handling difficult

Async/Await (Modern Way):

javascript

async function getUserAndPosts(userId) {


const user = await getUser(userId);
const posts = await getPosts([Link]);
return { user, posts };
}

const result = await getUserAndPosts(1);


[Link](result);
// Reads like synchronous code, easier error handling

Benefits of Async/Await:

Looks synchronous, easier to understand

Better error handling with try-catch

Easier debugging (better stack traces)

Avoids callback hell

More maintainable code

3. Why Use Promises Over Callbacks?


Promises provide:

Better error handling

Chaining instead of nesting


.finally() for cleanup

[Link]() , [Link]() for multiple async operations

More readable code flow

4. Why Use let/const Instead of var?


var Problems:

Function-scoped (confusing)

Hoisted and initialized as undefined (unexpected behavior)

Can be redeclared (accidental overwrites)

let/const Benefits:

Block-scoped (predictable)

Temporal Dead Zone (catches errors early)

Cannot be redeclared (prevents mistakes)

const prevents reassignment (safer defaults)

5. Why Use Arrow Functions in Some Cases?


Regular Functions:

this is dynamic (bound at call time)

Has arguments object

Can be used as constructors

Arrow Functions:

this is lexical (from parent scope)

No arguments object

Shorter syntax

Better for callbacks

Use Cases:

Arrow functions: callbacks, array methods, concise functions

Regular functions: object methods, constructors, when this binding needed


6. Why Use Closures?
Benefits:

Data privacy (encapsulation)

Function factories

Callback handlers

Module pattern

Example:

javascript

function createSecret(secret) {
return {
getSecret: () => secret,
// secret is private, cannot be accessed directly
};
}

const vault = createSecret("password123");


[Link]([Link]()); // "password123"
[Link]([Link]); // undefined

7. Why Use Prototypes Instead of Classes?


Classes are syntactic sugar over prototypes. Use:

Classes: For organized, readable OOP code

Prototypes: For deep understanding, legacy code, simple inheritance

Modern approach: Use classes for cleaner code.

8. Why Use Destructuring?


Before Destructuring:

javascript

const user = { name: 'John', age: 30 };


const name = [Link];
const age = [Link];
With Destructuring:

javascript

const { name, age } = user;

Benefits:

Less code

More readable

Better variable naming

Works in function parameters

9. Why Use Spread Operator?


Before:

javascript

const arr1 = [1, 2];


const arr2 = [3, 4];
const combined = [Link](arr2);

With Spread:

javascript

const combined = [...arr1, ...arr2];

Benefits:

Cleaner syntax

Works with both arrays and objects

Easy object cloning

Immutable operations

10. Why Use Higher-Order Functions?


Benefits:

Code reusability
Functional programming paradigm

Better abstraction

Cleaner callbacks

Example - Preventing repeated logic:

javascript

// Without HOF - repeated logic


function logAddition(a, b) {
[Link]('Adding...');
[Link](a + b);
}

function logMultiplication(a, b) {
[Link]('Multiplying...');
[Link](a * b);
}

// With HOF - DRY principle


function withLogging(fn, operation) {
return function(...args) {
[Link](`${operation}...`);
return fn(...args);
};
}

const logAdd = withLogging((a, b) => a + b, 'Adding');


const logMult = withLogging((a, b) => a * b, 'Multiplying');

11. Why Use map/filter/reduce Over forEach?


forEach is imperative (how):

javascript

const doubled = [];


[Link](n => [Link](n * 2));

map is declarative (what):

javascript

const doubled = [Link](n => n * 2);


Benefits:

Functional programming style

Cleaner, more readable

Chainable (map → filter → reduce)

Returns new array (immutable)

12. Why Immutability Matters


Mutable (problematic):

javascript

const arr = [1, 2, 3];


[Link](4); // Modifies original

Immutable (safer):

javascript

const arr = [1, 2, 3];


const newArr = [...arr, 4]; // Original unchanged

Benefits:

Prevents bugs

Easier to track changes

Better for React/Redux

Thread-safe in multi-threaded environments

13. Why Use Event Delegation?


Without Delegation (inefficient):

javascript

const items = [Link]('li');


[Link](item => {
[Link]('click', handler); // Many listeners
});
With Delegation (efficient):

javascript

const list = [Link]('ul');


[Link]('click', (e) => {
if ([Link] === 'LI') {
handler(e);
}
}); // Single listener

Benefits:

Better performance

Handles dynamic elements

Less memory usage

14. Why Use try-catch for Async Errors?


Promises without catch (risky):

javascript

fetch('/api').then(response => [Link]());


// Unhandled rejection if fetch fails

With Async/Await and try-catch (safe):

javascript

try {
const response = await fetch('/api');
const data = await [Link]();
} catch (error) {
[Link]('Handled error:', error);
}

Benefits:

Centralized error handling

Prevents unhandled rejections

Works like synchronous try-catch

Easier debugging
15. Why Event Bubbling and Capturing Matter?
Understanding event propagation prevents:

Unexpected event triggers

Performance issues

Unintended side effects

Practical use:

javascript

// Prevent bubbling for nested buttons


[Link]('click', (e) => {
[Link](); // Doesn't trigger parent's click
});

16. Why Clone Objects Instead of Assigning?


Direct assignment (shared reference):

javascript

const obj1 = { name: 'John' };


const obj2 = obj1;
[Link] = 'Jane';
[Link]([Link]); // 'Jane' - both changed!

Cloning (independent):

javascript

const obj1 = { name: 'John' };


const obj2 = { ...obj1 };
[Link] = 'Jane';
[Link]([Link]); // 'John' - original safe

Benefits:

Prevents accidental mutations

Pure functions

Predictable behavior
17. Why Use typeof vs instanceof?
typeof - Primitive Types:

javascript

typeof 42 // 'number'
typeof 'hello' // 'string'
typeof true // 'boolean'
typeof undefined // 'undefined'

instanceof - Objects/Classes:

javascript

[] instanceof Array // true


{} instanceof Object // true
new Date() instanceof Date // true

Difference:

typeof for primitives and functions

instanceof for objects and class instances

18. Why Use [Link] for Constants?


Regular object (can be modified):

javascript

const config = { apiUrl: '[Link] };


[Link] = '[Link] // Changed!

Frozen object (immutable):

javascript

const config = [Link]({ apiUrl: '[Link] });


[Link] = '[Link] // Fails silently

Benefits:

Prevents accidental modifications


Explicit intent (this shouldn't change)

Catches errors in strict mode

19. Why Does 'this' Binding Matter?


Incorrect this binding causes common bugs:

javascript

// Problem
const obj = {
name: 'John',
greet: function() {
setTimeout(function() {
[Link]([Link]); // undefined - 'this' is window
}, 100);
}
};

// Solution 1: Arrow function


const obj2 = {
name: 'John',
greet: function() {
setTimeout(() => {
[Link]([Link]); // 'John' - arrow inherits 'this'
}, 100);
}
};

// Solution 2: bind
const obj3 = {
name: 'John',
greet: function() {
setTimeout(function() {
[Link]([Link]); // 'John' - bound to obj3
}.bind(this), 100);
}
};

Key Point: Understanding this prevents subtle bugs in callbacks.

20. Why Temporal Dead Zone Exists?


var hoisting (confusing):
javascript

[Link](x); // undefined (confusing!)


var x = 5;

let/const Temporal Dead Zone (safe):

javascript

[Link](y); // ReferenceError - catches error early


let y = 5;

Benefits:

Forces declaration before use

Prevents accidental undefined values

Catches typos and mistakes early

Summary: Key Takeaways

Best Practices:
1. Use const by default, let when needed, avoid var

2. Use async/await instead of callbacks or raw promises

3. Use arrow functions for callbacks, regular functions for methods

4. Use destructuring for cleaner variable assignment

5. Use spread operator for immutable operations

6. Use === instead of ==

7. Use try-catch with async/await for error handling

8. Use event delegation for dynamic elements

9. Clone objects with spread or [Link]

10. Use map/filter/reduce for functional programming

JavaScript Strengths:
Frontend: Runs natively in browsers

Full-stack: Same language frontend and backend

Async-first: Built for asynchronous operations


Flexible: Supports multiple programming paradigms

Ecosystem: Largest package manager (npm)

Common Interview Questions Answered:


Question Answer

What's hoisting? Moving declarations to top of scope

What's closure? Function with access to outer scope

What's this ? Depends on how function is called

Why use async/await? Cleaner than callbacks or promises

Why use const? Prevents reassignment, default choice

What's the event loop? Manages async operations and execution order

Why use arrow functions? Shorter syntax, lexical this binding

What's prototype chain? How objects inherit properties

Why use destructuring? Cleaner, shorter code

Why use spread? Immutable operations, easier syntax


 

Practice Exercise: Build a Mini Project


Create a simple task manager with the concepts learned:

javascript
// Using: Classes, Closures, Array Methods, Error Handling, DOM Events

class TaskManager {
#tasks = []; // Private field

constructor() {
[Link]();
[Link]();
[Link]();
}

addTask(title) {
if (![Link]()) {
throw new Error("Task cannot be empty");
}

const task = {
id: [Link](),
title: title,
completed: false,
createdAt: new Date()
};

this.#[Link](task);
[Link]();
[Link]();
}

removeTask(id) {
this.#tasks = this.#[Link](task => [Link] !== id);
[Link]();
[Link]();
}

toggleTask(id) {
const task = this.#[Link](task => [Link] === id);
if (task) {
[Link] = ![Link];
[Link]();
[Link]();
}
}

getTasks() {
return [...this.#tasks]; // Return copy for data privacy
}
setupEventListeners() {
const input = [Link]('#taskInput');
const button = [Link]('#addBtn');
const list = [Link]('#taskList');

[Link]('click', () => {
try {
[Link]([Link]);
[Link] = '';
} catch (error) {
alert([Link]);
}
});

[Link]('keypress', (e) => {


if ([Link] === 'Enter') {
[Link]();
}
});

// Event Delegation
[Link]('click', (e) => {
const taskId = parseInt([Link]);

if ([Link]('toggle-btn')) {
[Link](taskId);
} else if ([Link]('delete-btn')) {
[Link](taskId);
}
});
}

render() {
const list = [Link]('#taskList');
[Link] = '';

this.#tasks
.map(task => [Link](task))
.forEach(element => [Link](element));
}

createTaskElement(task) {
const li = [Link]('li');
[Link] = `
<span class="${[Link] ? 'completed' : ''}">${[Link]}</span>
<button class="toggle-btn" data-id="${[Link]}">Toggle</button>
<button class="delete-btn" data-id="${[Link]}">Delete</button>
`;
return li;
}

saveToStorage() {
// Using JSON for storage (in real app, use localStorage carefully)
[Link]('Tasks saved:', this.#tasks);
}

loadFromStorage() {
// Load from storage if available
[Link]('Tasks loaded');
}
}

// Usage
const manager = new TaskManager();

This demonstrates:

✅ Classes and private fields


✅ Closures and data privacy
✅ Array methods (map, filter, find)
✅ Error handling (try-catch)
✅ DOM manipulation
✅ Event delegation
✅ Immutability (spread operator)
✅ Higher-order functions (map)

Congratulations! You now have comprehensive knowledge of the 30-40 most important JavaScript topics and
the reasoning behind them. Use this guide as a reference for interviews and real-world development.

You might also like