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.