Exercise 1: Declare and Assign Variables
// Exercise 1: Declare and Assign Variables
let userName = "Alice"; // Declaring a string variable [cite: 7, 8]
const favoriteNumber = 7; // Declaring a number constant
[Link]("User Name:", userName);
[Link]("Favorite Number:", favoriteNumber);
Exercise 2: Basic Arithmetic Operations
// Exercise 2: Basic Arithmetic Operations
let num1 = 10;
let num2 = 5;
let sum = num1 + num2;
let difference = num1 - num2;
let product = num1 * num2;
let quotient = num1 / num2;
[Link]("Sum:", sum);
[Link]("Difference:", difference);
[Link]("Product:", product);
[Link]("Quotient:", quotient);
Exercise 3: String Concatenation
// Exercise 3: String Concatenation
let firstName = "John";
let lastName = "Doe";
// Method 1: Using the + operator
let fullName = firstName + " " + lastName;
[Link]("Full Name (using +):", fullName);
// Method 2: Using template literals (recommended for complex strings)
let fullGreeting = `Hello, my name is ${firstName} ${lastName}!`;
[Link]("Full Greeting (using template literal):", fullGreeting);
Exercise 4: Conditional Statement (If/Else)
Laurence Svekis Learn More [Link]
// Exercise 4: Conditional Statement (If/Else)
let age = 20;
// Try changing this value to 16, 18, 25
if (age >= 18) {
[Link]("You are an adult.");
} else {
[Link]("You are a minor.");
}
let anotherAge = 16;
if (anotherAge >= 18) {
[Link]("You are an adult. (for anotherAge)");
} else {
[Link]("You are a minor. (for anotherAge)");
}
Exercise 5: Conditional Statement (If/Else If/Else)
// Exercise 5: Conditional Statement (If/Else If/Else)
let score = 85;
// Try changing this value (e.g., 95, 72, 55)
let grade;
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else if (score >= 70) {
grade = "C";
} else if (score >= 60) {
grade = "D";
} else {
grade = "F";
}
[Link](`With a score of ${score}, your grade is: ${grade}`);
Exercise 6: For Loop (Basic Iteration)
// Exercise 6: For Loop (Basic Iteration)
Laurence Svekis Learn More [Link]
[Link]("Numbers from 1 to 10:");
for (let i = 1; i <= 10; i++) {
[Link](i);
}
Exercise 7: While Loop (Conditional Iteration)
// Exercise 7: While Loop (Conditional Iteration)
let count = 5;
[Link]("Countdown from 5:");
while (count >= 1) {
[Link](count);
count--; // Decrement count by 1
}
[Link]("Blast off!");
Exercise 8: Simple Function Definition and Call
// Exercise 8: Simple Function Definition and Call
function greet(name) {
[Link](`Hello, ${name}!`);
}
// Call the function
greet("Alice");
greet("Bob");
greet("Charlie");
Exercise 9: Function with Return Value
// Exercise 9: Function with Return Value
function addNumbers(a, b) {
return a + b;
}
// Call the function and store its result
let result1 = addNumbers(5, 3);
[Link]("Sum of 5 and 3:", result1); // Expected: 8
let result2 = addNumbers(100, 20);
Laurence Svekis Learn More [Link]
[Link]("Sum of 100 and 20:", result2);
// Expected: 120
Exercise 10: Introduction to Arrays
// Exercise 10: Introduction to Arrays
let fruits = ["Apple", "Banana", "Orange"];
[Link]("Original fruits array:", fruits);
// Accessing elements by index (arrays are zero-indexed)
[Link]("First fruit:", fruits[0]); // "Apple"
[Link]("Second fruit:", fruits[1]);
// "Banana"
[Link]("Third fruit:", fruits[2]); // "Orange"
// Accessing the last element using .length property
[Link]("Last fruit:", fruits[[Link] - 1]);
// "Orange"
// Adding an element to the end of the array
[Link]("Grape");
[Link]("Fruits array after adding 'Grape':", fruits);
[Link]("New last fruit:", fruits[[Link] - 1]); // "Grape"
[Link]("Total number of fruits:", [Link]); // 4
Exercise 11: Iterating Over an Array with For Loop
// Exercise 11: Iterating Over an Array with For Loop
let numbers = [10, 20, 30, 40, 50];
[Link]("Numbers in the array:");
for (let i = 0; i < [Link]; i++) {
[Link](numbers[i]);
}
Exercise 12: Iterating Over an Array with For...of Loop
// Exercise 12: Iterating Over an Array with For...of Loop
let numbers = [10, 20, 30, 40, 50];
[Link]("Numbers in the array (using for...of):");
for (let number of numbers) { // 'number' here directly gets each element's value
Laurence Svekis Learn More [Link]
[Link](number);
}
Exercise 13: Array Method: forEach()
// Exercise 13: Array Method: forEach()
let names = ["Alice", "Bob", "Charlie"];
[Link]("Greetings:");
[Link](function(name) { // The function here is a "callback"
[Link](`Hello, ${name}!`);
});
// Using arrow function syntax (more common in modern JS)
[Link]("\nGreetings (using arrow function):");
[Link](name => {
[Link](`Hi there, ${name}.`);
});
Exercise 14: Object Basics
// Exercise 14: Object Basics
let person = {
name: "John Doe",
age: 30,
isStudent: false,
"favorite color": "blue" // Property with a space in its name
};
[Link]("Person's details:");
[Link]("Name:", [Link]); // Accessing with dot notation
[Link]("Age:", person["age"]); // Accessing with bracket notation
[Link]("Is Student:", [Link]);
// Accessing property with a space in its name (only bracket notation works)
[Link]("Favorite Color:", person["favorite color"]);
// Modifying a property
[Link] = 31;
[Link]("Updated Age:", [Link]); // Adding a new property
[Link] = "New York";
[Link]("City:", [Link]);
Laurence Svekis Learn More [Link]
[Link]("Updated Person object:", person);
Exercise 15: Function with Object as Argument
// Exercise 15: Function with Object as Argument
function displayBookInfo(book) {
[Link](`Book: ${[Link]} by ${[Link]}`);
}
// Optional: Using object destructuring in function parameters
function displayBookInfoDestructured({ title, author }) {
[Link](`Book (destructured): ${title} by ${author}`);
}
let myBook = {
title: "The Great Gatsby",
author: "F. Scott Fitzgerald",
year: 1925
};
let anotherBook = {
title: "1984",
author: "George Orwell",
pages: 328
};
displayBookInfo(myBook);
displayBookInfo(anotherBook);
// Even if 'pages' is present, function only uses 'title' and 'author'
displayBookInfoDestructured(myBook);
Exercise 16: Array of Objects
// Exercise 16: Array of Objects
let students = [
{ name: "Alice", grade: 92 },
{ name: "Bob", grade: 78 },
{ name: "Charlie", grade: 85 },
{ name: "Diana", grade: 60 }
];
[Link]("Student Grades:");
Laurence Svekis Learn More [Link]
for (let student of students) {
[Link](`${[Link]}: ${[Link]}`);
}
// Using forEach
[Link]("\nStudent Grades (using forEach):");
[Link](student => {
[Link](`- ${[Link]} got a ${[Link]}`);
});
Exercise 17: Basic String Methods
// Exercise 17: Basic String Methods
let message = "Hello JavaScript World";
[Link]("Original Message:", message);
[Link]("Length of message:", [Link]); // 22
[Link]("Uppercase:", [Link]()); // "HELLO JAVASCRIPT WORLD"
[Link]("Lowercase:", [Link]());
// "hello javascript world"
// Finding the index of a substring
let jsIndex = [Link]("JavaScript");
[Link]("Index of 'JavaScript':", jsIndex);
// 6 (index where 'J' starts)
// Extracting a substring using slice()
// slice(startIndex, endIndex - 1)
let extractedWord = [Link](jsIndex, jsIndex + "JavaScript".length);
[Link]("Extracted word:", extractedWord); // "JavaScript"
// Check if a string includes a substring
[Link]("Does message include 'World'?", [Link]("World"));
// true
Exercise 18: Function to Reverse a String
// Exercise 18: Function to Reverse a String
function reverseString(str) {
let reversedStr = "";
for (let i = [Link] - 1; i >= 0; i--) {
reversedStr += str[i];
Laurence Svekis Learn More [Link]
// Append character to the reversed string
}
return reversedStr;
}
// Alternative using array methods (more advanced, but common)
function reverseStringMethod(str) {
return [Link]('').reverse().join('');
}
[Link]("Reversed 'hello':", reverseString("hello")); // Expected: "olleh"
[Link]("Reversed 'world':", reverseString("world")); // Expected: "dlrow"
[Link]("Reversed 'JavaScript':", reverseString("JavaScript"));
// Expected: "tpircSavaJ"
[Link]("Reversed 'hello' (method):", reverseStringMethod("hello"));
Exercise 19: Find the Largest Number in an Array
// Exercise 19: Find the Largest Number in an Array
function findLargestNumber(numbers) {
if ([Link] === 0) {
return undefined;
// Or throw an error, or return a specific value
}
let largest = numbers[0];
// Assume the first element is the largest initially
for (let i = 1; i < [Link]; i++) { // Start from the second element
if (numbers[i] > largest) {
largest = numbers[i];
// Update largest if current number is greater
}
}
return largest;
}
[Link]("Largest in [3, 8, 1, 12, 5]:", findLargestNumber([3, 8, 1, 12, 5]));
// Expected: 12
[Link]("Largest in [100, 20, 30]:", findLargestNumber([100, 20, 30])); //
Expected: 100
[Link]("Largest in [7]:", findLargestNumber([7]));
// Expected: 7
Laurence Svekis Learn More [Link]
[Link]("Largest in []:", findLargestNumber([])); // Expected: undefined (due to
added check)
Exercise 20: Calculate the Sum of Array Elements
// Exercise 20: Calculate the Sum of Array Elements
function calculateSum(numbers) {
let totalSum = 0;
// Initialize sum to zero
for (let i = 0; i < [Link]; i++) {
totalSum += numbers[i];
// Add current number to totalSum
}
return totalSum;
}
// Alternative using for...of loop
function calculateSumForOf(numbers) {
let totalSum = 0;
for (let num of numbers) {
totalSum += num;
}
return totalSum;
}
// Alternative using reduce() (more advanced)
function calculateSumReduce(numbers) {
return [Link]((accumulator, currentValue) => accumulator + currentValue,
0);
}
[Link]("Sum of [1, 2, 3, 4, 5]:", calculateSum([1, 2, 3, 4, 5]));
// Expected: 15
[Link]("Sum of [10, 20, 30]:", calculateSumForOf([10, 20, 30])); // Expected: 60
[Link]("Sum of []:", calculateSum([]));
// Expected: 0
[Link]("Sum of [7, 8, 9] (reduce):", calculateSumReduce([7, 8, 9])); // Expected: 24
Exercise 21: Array Method: filter()
Laurence Svekis Learn More [Link]
// Exercise 21: Array Method: filter()
let data = [10, 25, 30, 45, 50, 65, 5, 80];
// Filter numbers greater than 40
let greaterThan40 = [Link](function(number) {
return number > 40;
});
[Link]("Numbers greater than 40:", greaterThan40); // Expected: [45, 50, 65, 80]
// Using arrow function syntax
let evenNumbers = [Link](number => number % 2 === 0);
[Link]("Even numbers:", evenNumbers); // Expected: [10, 30, 50, 80]
// Filtering objects in an array
let products = [
{ name: "Laptop", price: 1200 },
{ name: "Mouse", price: 25 },
{ name: "Keyboard", price: 75 },
{ name: "Monitor", price: 300 }
];
let expensiveProducts = [Link](product => [Link] > 100);
[Link]("Expensive products (> $100):", expensiveProducts);
// Expected: [{ name: "Laptop", price: 1200 }, { name: "Monitor", price: 300 }]
Exercise 22: Array Method: map()
// Exercise 22: Array Method: map()
let prices = [10, 20, 30, 45];
// Double each price
let doubledPrices = [Link](function(price) {
return price * 2;
});
[Link]("Doubled prices:", doubledPrices);
// Expected: [20, 40, 60, 90]
// Using arrow function syntax
let pricesWithTax = [Link](price => price * 1.05);
// Add 5% tax
[Link]("Prices with 5% tax:", pricesWithTax); // Mapping an array of objects to
get specific properties
let users = [
{ id: 1, name: "Alice", email: "alice@[Link]" },
Laurence Svekis Learn More [Link]
{ id: 2, name: "Bob", email: "bob@[Link]" },
{ id: 3, name: "Charlie", email: "charlie@[Link]" }
];
let userNames = [Link](user => [Link]);
[Link]("User names:", userNames); // Expected: ["Alice", "Bob", "Charlie"]
Exercise 23: Array Method: reduce()
// Exercise 23: Array Method: reduce()
let items = [5, 10, 15, 20];
// Summing all numbers in an array
let sum = [Link](function(accumulator, currentValue) {
[Link](`Accumulator: ${accumulator}, Current Value: ${currentValue}`);
return accumulator + currentValue;
}, 0);
// 0 is the initial value for the accumulator
[Link]("Sum of items:", sum);
// Expected: 50
// Using arrow function syntax (common)
let product = [Link]((acc, val) => acc * val, 1);
// Initial value for product is 1
[Link]("Product of items:", product);
// Expected: 5 * 10 * 15 * 20 = 15000
// Reducing an array of objects to a single value
let cart = [
{ item: "Shirt", price: 25 },
{ item: "Jeans", price: 60 },
{ item: "Socks", price: 10 }
];
let totalCartPrice = [Link]((total, currentItem) => total + [Link], 0);
[Link]("Total cart price:", totalCartPrice);
// Expected: 95
Exercise 24: Closures
// Exercise 24: Closures
function makeCounter() {
Laurence Svekis Learn More [Link]
let count = 0;
// 'count' is in the outer function's scope
return function() { // This inner function forms a closure
count++;
// It "remembers" and can access 'count' from its lexical environment
return count;
};
}
let counter1 = makeCounter(); // counter1 is now the inner function returned by
makeCounter()
[Link]("Counter 1:");
[Link](counter1());
// Expected: 1
[Link](counter1()); // Expected: 2
[Link](counter1()); // Expected: 3
let counter2 = makeCounter();
// A new, independent counter
[Link]("\nCounter 2:");
[Link](counter2()); // Expected: 1 (starts fresh)
[Link](counter1());
// Expected: 4 (counter1 continues independently)
Exercise 25: Basic Object-Oriented Programming
(Constructor Function / Class)
// Exercise 25: Basic Object-Oriented Programming (Constructor Function)
// Using a Constructor Function (traditional ES5 way)
function Car(make, model) {
[Link] = make;
[Link] = model;
}
// Add a method to the Car's prototype
// This ensures all instances share the same method, saving memory
[Link] = function() {
[Link](`This is a ${[Link]} ${[Link]}.`);
};
// Create instances
let car1 = new Car("Toyota", "Camry");
Laurence Svekis Learn More [Link]
let car2 = new Car("Honda", "Civic");
[Link]();
// Expected: "This is a Toyota Camry."
[Link](); // Expected: "This is a Honda Civic."
// --- Using ES6 Class Syntax (modern way, syntactic sugar over prototypes) ---
class Motorcycle {
constructor(brand, type) {
[Link] = brand;
[Link] = type;
}
displayDetails() {
[Link](`This is a ${[Link]} ${[Link]} motorcycle.`);
}
}
let moto1 = new Motorcycle("Harley-Davidson", "Sportster");
let moto2 = new Motorcycle("Kawasaki", "Ninja");
[Link]();
[Link]();
Exercise 26: Asynchronous JavaScript - Callbacks
(Simulated)
// Exercise 26: Asynchronous JavaScript - Callbacks (Simulated)
function fetchUserData(userId, callback) {
[Link](`Fetching data for user ID: ${userId}...`);
// Simulate an asynchronous operation (e.g., network request)
setTimeout(() => {
const user = {
id: userId,
name: `User ${userId}`,
email: `user${userId}@[Link]`
};
[Link](`Data for user ${userId} received.`);
callback(user); // Execute the callback with the fetched data
}, 2000);
// Simulate a 2-second delay
}
// How to use it:
Laurence Svekis Learn More [Link]
[Link]("Starting data fetch for User 1.");
fetchUserData(1, function(user) {
[Link]("Processing fetched user data:");
[Link]("User Name:", [Link]);
[Link]("User Email:", [Link]);
});
[Link]("\nStarting data fetch for User 2.");
fetchUserData(2, (user) => { // Using arrow function for callback
[Link]("Processing fetched user data for User 2:");
[Link]("User ID:", [Link]);
});
[Link]("Requests initiated. This message appears first because the fetch is
async.");
// The "Requests initiated..." message will appear immediately,
// before the "Data received" messages, demonstrating asynchronicity.
Exercise 27: Asynchronous JavaScript - Promises
(Basic)
// Exercise 27: Asynchronous JavaScript - Promises (Basic)
function fetchUserDataPromise(userId) {
[Link](`(Promise) Fetching data for user ID: ${userId}...`);
return new Promise((resolve, reject) => { // A Promise takes a function with resolve
and reject
setTimeout(() => {
if (userId === 0) {
reject("User with ID 0 not found."); // Simulate an error
return;
}
const user = {
id: userId,
name: `Promise User ${userId}`,
status: "active"
};
[Link](`(Promise) Data for user ${userId} received.`);
resolve(user); // Resolve the promise with the user data
}, 2000);
});
Laurence Svekis Learn More [Link]
}
// Using the Promise:
[Link]("--- Fetching User 1 (Success Case) ---");
fetchUserDataPromise(1)
.then((user) => { // .then() is called when the promise resolves
[Link]("Success! User 1 Data:", user);
[Link](`Resolved User 1 Name: ${[Link]}`);
})
.catch((error) => { // .catch() is called when the promise rejects
[Link]("Error fetching User 1:", error);
});
[Link]("\n--- Fetching User 0 (Error Case) ---");
fetchUserDataPromise(0)
.then((user) => {
[Link]("Success! User 0 Data:", user); // This block will NOT execute
})
.catch((error) => {
[Link]("Error fetching User 0:", error); // This block WILL execute
});
[Link]("Promise requests initiated. This message appears first.");
Exercise 28: Recursion - Factorial Calculation
// Exercise 28: Recursion - Factorial Calculation
function factorial(n) {
// Base case: When to stop the recursion
if (n === 0 || n === 1) {
return 1;
}
// Recursive step: Call the function itself with a smaller problem
else {
return n * factorial(n - 1);
}
}
[Link]("Factorial of 0:", factorial(0)); // Expected: 1
[Link]("Factorial of 1:", factorial(1)); // Expected: 1
[Link]("Factorial of 5:", factorial(5));
// Expected: 120 (5 * 4 * 3 * 2 * 1)
Laurence Svekis Learn More [Link]
[Link]("Factorial of 7:", factorial(7));
// Expected: 5040
// [Link]("Factorial of -1:", factorial(-1)); // This would lead to infinite recursion
without proper handling
Exercise 29: Higher-Order Function - map() with
Objects
// Exercise 29: Higher-Order Function - map() with Objects
let products = [
{ id: 1, name: "Laptop", price: 1200, category: "Electronics" },
{ id: 2, name: "Mouse", price: 25, category: "Electronics" },
{ id: 3, name: "Notebook", price: 15, category: "Stationery" },
{ id: 4, name: "Desk Chair", price: 250, category: "Furniture" }
];
// Add a priceWithTax property to each product
const TAX_RATE = 0.15;
let productsWithTax = [Link](product => {
return {
...product, // Copies all existing properties from the original product object
priceWithTax: [Link] * (1 + TAX_RATE) // Adds the new property
};
});
[Link]("Products with Tax:", productsWithTax);
/* Expected Output Structure (approx):
[
{ id: 1, name: "Laptop", price: 1200, category: "Electronics", priceWithTax: 1380 },
{ id: 2, name: "Mouse", price: 25, category: "Electronics", priceWithTax: 28.75 },
...
] */
// Transform products into a simplified list for display
let productTitles = [Link](product => `${[Link]} ($${[Link]})`);
[Link]("\nProduct Titles:", productTitles); // Expected: ["Laptop ($1200)", "Mouse
($25)", ...]
Exercise 30: Chaining Array Methods
Laurence Svekis Learn More [Link]
// Exercise 30: Chaining Array Methods
let transactions = [
{ id: 1, amount: 100, type: 'credit', date: '2023-01-01' },
{ id: 2, amount: 50, type: 'debit', date: '2023-01-02' },
{ id: 3, amount: 200, type: 'credit', date: '2023-01-03' },
{ id: 4, amount: 30, type: 'debit', date: '2023-01-04' },
{ id: 5, amount: 150, type: 'credit', date: '2023-01-05' }
];
// Calculate the total amount of all credit transactions
let totalCreditAmount = transactions
.filter(transaction => [Link] === 'credit') // Step 1: Filter credit transactions
.map(creditTransaction => [Link]) // Step 2: Extract amounts
.reduce((sum, amount) => sum + amount, 0);
// Step 3: Sum the amounts
[Link]("Transactions:", transactions);
[Link]("Total Credit Amount:", totalCreditAmount);
// Expected: 100 + 200 + 150 = 450
// Another example: Get names of users older than 25
let people = [
{ name: "Alice", age: 20 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 25 },
{ name: "Diana", age: 35 }
];
let namesOfAdults = people
.filter(person => [Link] > 25)
.map(adult => [Link]);
[Link]("\nNames of people older than 25:", namesOfAdults); // Expected: ["Bob",
"Diana"]
Exercise 31: Error Handling with try...catch
// Exercise 31: Error Handling with try...catch
function divide(a, b) {
try {
if (b === 0) {
throw new Error("Cannot divide by zero.");
// Throw an error if b is 0
Laurence Svekis Learn More [Link]
}
return a / b;
// Perform division if b is not 0
} catch (error) {
[Link]("An error occurred:", [Link]);
// Catch and log the error message
return NaN;
// Return Not-a-Number or some other indicative value
}
}
[Link]("10 / 2 =", divide(10, 2));
// Expected: 5
[Link]("7 / 0 =", divide(7, 0)); // Expected: An error message and NaN
[Link]("15 / 3 =", divide(15, 3));
// Expected: 5
Exercise 32: Understanding this Keyword Context
// Exercise 32: Understanding 'this' Keyword Context
let calculator = {
value: 0, // Initial value
// Method to add a number to the current value
add: function(num) {
[Link] += num;
// 'this' refers to the 'calculator' object
return this;
// Return 'this' to allow method chaining
},
// Method to get the current result
getResult: function() {
return [Link];
// 'this' refers to the 'calculator' object
},
// Example of 'this' context changing inside a regular function
// (This will be clarified with arrow functions later)
debugValueLater: function() {
setTimeout(function() {
// [Link]("Value inside setTimeout (problematic 'this'):", [Link]);
Laurence Svekis Learn More [Link]
// In strict mode (default for modules), 'this' here would be undefined.
// In non-strict mode (old browsers), 'this' would be the global object
(window/global).
// This highlights why arrow functions are often preferred for callbacks.
}, 100);
}
};
// Demonstrate method chaining
let finalResult = [Link](5).add(10).add(20).getResult();
[Link]("Chained result:", finalResult);
// Expected: 35
// Reset and try another sequence
[Link] = 0;
// Reset for a new calculation
let anotherResult = [Link](2).add(3).getResult();
[Link]("Another result:", anotherResult);
// Expected: 5
Exercise 33: Arrow Functions (=>)
// Exercise 33: Arrow Functions (=>)
// Example 1: `forEach` with arrow function
let numbers = [1, 2, 3, 4, 5];
[Link]("Numbers via forEach (arrow function):");
[Link](num => [Link](num * 2));
// Concise syntax for single expression
// Example 2: `map` with arrow function
let names = ["Alice", "Bob", "Charlie"];
let uppercasedNames = [Link](name => [Link]());
[Link]("Uppercased names (arrow function):", uppercasedNames);
// Example 3: Arrow functions and `this` binding (lexical `this`)
let person = {
name: "John Doe",
// Regular function for method definition
greetDelayed: function() {
[Link](`Hello from ${[Link]}!`);
// 'this' correctly refers to 'person'
// Using an arrow function for the setTimeout callback
Laurence Svekis Learn More [Link]
// Arrow functions do NOT bind their own 'this'.
// They inherit 'this' from the enclosing (lexical) scope.
setTimeout(() => {
[Link](`Delayed greeting from ${[Link]}.`); // 'this' still refers to 'person'
}, 1000);
// For comparison: if you used a regular function here, 'this' would be different
setTimeout(function() {
// [Link](`Problematic delayed greeting from ${[Link]}.`);
// 'this' would be 'window' or 'undefined' in strict mode
}, 1200);
}
};
[Link]();
Exercise 34: Object Destructuring
// Exercise 34: Object Destructuring
let movie = {
title: "Inception",
director: "Christopher Nolan",
year: 2010,
rating: 8.8
};
// 1. Basic destructuring
const { title, director } = movie;
[Link]("Title:", title); // Expected: Inception
[Link]("Director:", director);
// Expected: Christopher Nolan
// 2. Destructuring with renaming
const { year, rating: imdbRating } = movie;
[Link]("Year:", year);
// Expected: 2010
[Link]("IMDB Rating:", imdbRating); // Expected: 8.8 (using new variable name)
// 3. Destructuring with default values for non-existent properties
const { genre = "Sci-Fi", producer = "Unknown" } = movie;
[Link]("Genre (with default):", genre); // Expected: Sci-Fi
[Link]("Producer (with default):", producer);
// Expected: Unknown
Laurence Svekis Learn More [Link]
// Destructuring in function parameters (common use case)
function displayMovieDetails({ title, director, year, runtime = "N/A" }) {
[Link](`\nDetails: ${title} (${year}) by ${director}. Runtime: ${runtime}`);
}
displayMovieDetails(movie);
displayMovieDetails({ title: "Avatar", director: "James Cameron", year: 2009 });
// No runtime provided
Exercise 35: Array Destructuring
// Exercise 35: Array Destructuring
let rgb = ["red", "green", "blue", "alpha", "cyan"];
// 1. Basic destructuring
const [firstColor, secondColor] = rgb;
[Link]("First color:", firstColor); // Expected: red
[Link]("Second color:", secondColor);
// Expected: green
// 2. Skipping elements
const [, , thirdColor] = rgb;
// Skip first two elements with empty commas
[Link]("Third color:", thirdColor);
// Expected: blue
// 3. Rest pattern: collects remaining elements into a new array
const [primaryColor, ...otherColors] = rgb;
[Link]("Primary Color:", primaryColor); // Expected: red
[Link]("Other Colors:", otherColors); // Expected: ["green", "blue", "alpha",
"cyan"]
// Destructuring with default values
const [color1, color2, color3, color4, color5 = "magenta"] = rgb;
[Link]("Color 5 (with default):", color5); // Expected: magenta (if not enough
elements)
// Swapping variables easily with destructuring
let x = 10;
let y = 20;
[x, y] = [y, x]; // Swap x and y without a temporary variable
[Link](`\nSwapped: x = ${x}, y = ${y}`);
// Expected: x = 20, y = 10
Laurence Svekis Learn More [Link]
Exercise 36: Spread Operator (...) - Arrays
// Exercise 36: Spread Operator (...) - Arrays
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
// 1. Combining arrays
let combinedArr = [...arr1, ...arr2];
[Link]("Combined Array:", combinedArr);
// Expected: [1, 2, 3, 4, 5, 6]
let moreCombined = [0, ...arr1, 10, ...arr2, 7];
[Link]("More Combined:", moreCombined);
// Expected: [0, 1, 2, 3, 10, 4, 5, 6, 7]
// 2. Copying arrays (shallow copy)
let arr1Copy = [...arr1];
[Link]("Array 1 Copy:", arr1Copy); // Expected: [1, 2, 3]
// Verify it's a copy (modifying copy doesn't affect original)
[Link](99);
[Link]("Array 1 after copy modified:", arr1); // Expected: [1, 2, 3]
[Link]("Array 1 Copy after modification:", arr1Copy);
// Expected: [1, 2, 3, 99]
// 3. Passing array elements as function arguments
function sumAll(a, b, c) {
return a + b + c;
}
let numbersForSum = [10, 20, 30];
[Link]("Sum of numbersForSum (using spread):", sumAll(...numbersForSum));
// Expected: 60
// Using [Link]() with spread
let grades = [85, 92, 78, 95, 88];
[Link]("Max grade:", [Link](...grades));
// Expected: 95
Exercise 37: Spread Operator (...) - Objects
// Exercise 37: Spread Operator (...) - Objects
let user = { name: "Jane", age: 28 };
// 1. Copying objects and adding new properties
Laurence Svekis Learn More [Link]
let userCopy = { ...user, city: "London" };
// Creates a new object, copies properties, adds/overrides 'city'
[Link]("Original User:", user);
// Expected: { name: "Jane", age: 28 }
[Link]("User Copy:", userCopy);
// Expected: { name: "Jane", age: 28, city: "London" }
// 2. Merging objects
let address = { street: "123 Main St", zip: "10001" };
let contactInfo = { email: "jane@[Link]", phone: "555-1234" };
let userProfile = { ...user, ...address, ...contactInfo, occupation: "Engineer" };
[Link]("User Profile (merged):", userProfile);
/* Expected: {
name: "Jane", age: 28, street: "123 Main St",
zip: "10001", email: "jane@[Link]", phone: "555-1234",
occupation: "Engineer"
} */
// Handling conflicts (later properties override earlier ones)
let baseSettings = { theme: "dark", fontSize: 16 };
let userSettings = { fontSize: 18, notifications: true };
let finalSettings = { ...baseSettings, ...userSettings };
[Link]("Final Settings (conflict resolved):", finalSettings); // Expected: { theme:
"dark", fontSize: 18, notifications: true }
Exercise 38: Ternary Operator (Conditional Operator)
// Exercise 38: Ternary Operator (Conditional Operator)
let temperature1 = 30;
let weatherStatus1 = (temperature1 > 25) ?
"Hot" : "Cold";
[Link](`Temperature: ${temperature1}°C, Status: ${weatherStatus1}`); //
Expected: Hot
let temperature2 = 18;
let weatherStatus2 = (temperature2 > 25) ? "Hot" : "Cold";
[Link](`Temperature: ${temperature2}°C, Status: ${weatherStatus2}`);
// Expected: Cold
// Another example: Check if a user is logged in
let isLoggedIn = true;
let message = isLoggedIn ? "Welcome back!" : "Please log in.";
Laurence Svekis Learn More [Link]
[Link](message); // Expected: Welcome back!
// Nested ternary (use sparingly for readability)
let time = 14;
// 2 PM
let greeting = (time < 12) ? "Good morning!"
: (time < 18) ?
"Good afternoon!" : "Good evening!";
[Link](greeting); // Expected: Good afternoon!
Exercise 39: Nullish Coalescing Operator (??)
// Exercise 39: Nullish Coalescing Operator (??)
let userName1 = null;
let defaultName = "Guest";
const displayName1 = userName1 ?? defaultName; // Falls back if userName1 is null or
undefined
[Link]("Display Name 1 (null):", displayName1);
// Expected: Guest
let userName2 = undefined;
const displayName2 = userName2 ?? defaultName;
[Link]("Display Name 2 (undefined):", displayName2);
// Expected: Guest
let userName3 = "Alice";
const displayName3 = userName3 ?? defaultName;
[Link]("Display Name 3 (value):", displayName3);
// Expected: Alice
// --- Difference between ?? and ||
// The logical OR (||) operator considers `false`, `0`, `""` (empty string), `null`,
`undefined` as "falsy".
// The nullish coalescing operator (??) only considers `null` and `undefined` as
"nullish".
let valueZero = 0;
let valueEmptyString = "";
let valueFalse = false;
// Using ||
[Link]("\n--- Using || (Logical OR) ---");
[Link]("valueZero || 'Default':", valueZero || "Default"); // Expected: Default (0 is
falsy)
Laurence Svekis Learn More [Link]
[Link]("valueEmptyString || 'Default':", valueEmptyString || "Default");
// Expected: Default ("" is falsy)
[Link]("valueFalse || 'Default':", valueFalse || "Default");
// Expected: Default (false is falsy)
// Using ??
[Link]("\n--- Using ?? (Nullish Coalescing) ---");
[Link]("valueZero ?? 'Default':", valueZero ?? "Default"); // Expected: 0 (0 is not
nullish)
[Link]("valueEmptyString ?? 'Default':", valueEmptyString ?? "Default");
// Expected: "" ("" is not nullish)
[Link]("valueFalse ?? 'Default':", valueFalse ?? "Default");
// Expected: false (false is not nullish)
Exercise 40: Optional Chaining (?.)
// Exercise 40: Optional Chaining (?.)
let user1 = {
name: "Alice",
email: "alice@[Link]",
address: {
street: "123 Main St",
city: "Anytown"
}
};
let user2 = {
name: "Bob",
email: "bob@[Link]"
// No address property
};
let user3 = {
name: "Charlie",
contact: {
email: "charlie@[Link]"
}
};
// Safely access nested properties using optional chaining
[Link]("User 1 Street:", [Link]?.street);
// Expected: 123 Main St
Laurence Svekis Learn More [Link]
[Link]("User 2 Street:", [Link]?.street); // Expected: undefined (no error)
[Link]("User 1 Zip Code:", [Link]?.zipCode);
// Expected: undefined (property doesn't exist)
// Accessing a potentially non-existent nested object property
[Link]("User 1 Company Name:", [Link]?.name);
// Expected: undefined (no error)
[Link]("User 2 Company Name:", [Link]?.name);
// Expected: undefined (no error)
// Combining with Nullish Coalescing for a fallback
let user1City = [Link]?.city ?? "N/A";
let user2City = [Link]?.city ?? "N/A";
[Link]("User 1 City:", user1City); // Expected: Anytown
[Link]("User 2 City:", user2City);
// Expected: N/A
// Optional chaining with function calls
// If [Link] is undefined, it won't try to call .getEmail()
const getEmail = (usr) => [Link]?.getEmail?.();
// The method getEmail might not exist
[Link] = () => "charlie_from_method@[Link]";
[Link]("User 3 Email (from method):", getEmail(user3));
// Expected: charlie_from_method@[Link]
[Link] = undefined; // Remove the method
[Link]("User 3 Email (method removed):", getEmail(user3));
// Expected: undefined (no error)
Exercise 41: Asynchronous JavaScript - async/await
// Exercise 41: Asynchronous JavaScript - async/await
// Reusing the Promise-based function from Exercise 27
function fetchUserDataPromise(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId === 0) {
reject("User with ID 0 not found.");
return;
}
const user = {
id: userId,
Laurence Svekis Learn More [Link]
name: `Async User ${userId}`,
status: "active"
};
resolve(user);
}, 1500); // Shorter delay for quicker demonstration
});
}
// New function using async/await
async function displayUserAsync(userId) {
[Link](`\n(async/await) Attempting to fetch user ${userId}...`);
try {
const user = await fetchUserDataPromise(userId);
// Pause execution until the promise resolves
[Link](`(async/await) Successfully fetched user ${userId}:`, user);
} catch (error) {
[Link](`(async/await) Error fetching user ${userId}:`, error);
}
}
// Demonstrate usage
displayUserAsync(101);
// Success case
displayUserAsync(0); // Error case
displayUserAsync(102); // Another success case
[Link]("Main script continues to run while async functions are awaiting.");
Exercise 42: Classes and Inheritance
// Exercise 42: Classes and Inheritance
// Parent Class
class Shape {
constructor(color) {
[Link] = color;
}
displayColor() {
[Link](`The shape color is ${[Link]}.`);
}
}
// Child Class inheriting from Shape
Laurence Svekis Learn More [Link]
class Circle extends Shape {
constructor(color, radius) {
super(color);
// Call the parent class's constructor
[Link] = radius;
}
// Override the displayColor method from the parent class
displayColor() {
[Link](`The circle color is ${[Link]}.`);
}
// New method specific to Circle
calculateArea() {
return [Link] * [Link] * [Link];
}
}
// Child Class inheriting from Shape (another example)
class Rectangle extends Shape {
constructor(color, width, height) {
super(color);
[Link] = width;
[Link] = height;
}
calculateArea() {
return [Link] * [Link];
}
// Overriding a method and calling the super method
displayColor() {
[Link]();
// Call the parent's displayColor method
[Link](`This is a rectangle.`);
}
}
// Create instances
let genericShape = new Shape("Red");
[Link](); // Expected: The shape color is Red.
let myCircle = new Circle("Blue", 5);
[Link](); // Expected: The circle color is Blue. (Overridden method)
[Link]("Circle Area:", [Link]().toFixed(2));
// Expected: ~78.54
Laurence Svekis Learn More [Link]
let myRectangle = new Rectangle("Green", 4, 6);
[Link](); // Expected: The shape color is Green.
[Link]("Rectangle Area:", [Link]()); // Expected: 24
Exercise 43: Static Methods and Properties
// Exercise 43: Static Methods and Properties
class MathHelper {
// Static property
static PI = 3.14159;
// Static method: can be called directly on the class, not instances
static add(a, b) {
return a + b;
}
static multiply(a, b) {
return a * b;
}
// Instance method (requires an instance of MathHelper)
instanceMethod() {
[Link]("This is an instance method.");
}
}
// Accessing static property
[Link]("[Link]:", [Link]); // Expected: 3.14159
// Calling static methods
[Link]("[Link](5, 3):", [Link](5, 3));
// Expected: 8
[Link]("[Link](4, 6):", [Link](4, 6)); // Expected: 24
// Trying to call a static method on an instance will throw an error
// let myHelper = new MathHelper();
// [Link](1, 2); // TypeError: [Link] is not a function
// Calling an instance method (requires an instance)
let myHelper = new MathHelper();
[Link]();
Exercise 44: Getters and Setters
Laurence Svekis Learn More [Link]
// Exercise 44: Getters and Setters
class Product {
constructor(name, initialPrice) {
[Link] = name;
this._price = 0; // Conventionally, _ prefix indicates a private/protected property
[Link] = initialPrice;
// Use the setter to initialize with validation
}
// Getter for 'price'
get price() {
[Link](`Getting price for ${[Link]}...`);
return this._price;
}
// Setter for 'price'
set price(newPrice) {
[Link](`Attempting to set price for ${[Link]} to ${newPrice}...`);
if (typeof newPrice === 'number' && newPrice >= 0) {
this._price = newPrice;
[Link](`Price set successfully to ${newPrice}.`);
} else {
[Link](`Error: Invalid price value: ${newPrice}. Price must be a non-negative
number.`);
}
}
displayDetails() {
[Link](`${[Link]} - $${[Link](2)}`);
}
}
let laptop = new Product("Laptop", 1200);
[Link](); // Getting price... Laptop - $1200.00
[Link]("Laptop price is:", [Link]);
// Accessing as a property (invokes getter)
[Link] = 1250; // Setting price (invokes setter)
[Link]();
// Getting price... Laptop - $1250.00
[Link] = -50; // Invalid price (invokes setter, logs error)
[Link]();
// Still Laptop - $1250.00 (price not changed due to validation)
[Link] = "one thousand";
Laurence Svekis Learn More [Link]
// Invalid type (invokes setter, logs error)
[Link](); // Still Laptop - $1250.00
Exercise 45: Array Method: some()
// Exercise 45: Array Method: some()
let grades = [60, 75, 80, 90, 55, 62];
// Check if at least one grade is >= 90
let hasExcellentGrade = [Link](grade => grade >= 90);
[Link]("Are there any excellent grades (>= 90)?", hasExcellentGrade); //
Expected: true
let grades2 = [50, 60, 70, 80];
let hasExcellentGrade2 = [Link](grade => grade >= 90);
[Link]("Are there any excellent grades (>= 90) in grades2?",
hasExcellentGrade2);
// Expected: false
// Check if any product is out of stock (using objects)
let products = [
{ name: "Milk", inStock: true },
{ name: "Bread", inStock: false },
{ name: "Eggs", inStock: true }
];
let anyOutOfStock = [Link](product => ![Link]);
[Link]("Is any product out of stock?", anyOutOfStock);
// Expected: true
let allInStockProducts = [
{ name: "Apples", inStock: true },
{ name: "Bananas", inStock: true }
];
let anyOutOfStock2 = [Link](product => ![Link]);
[Link]("Is any product out of stock (all in stock)?", anyOutOfStock2);
// Expected: false
Exercise 46: Array Method: every()
// Exercise 46: Array Method: every()
let ages = [22, 28, 35, 40, 19];
Laurence Svekis Learn More [Link]
// Check if all ages are >= 18
let allAdults = [Link](age => age >= 18);
[Link]("Are all ages >= 18?", allAdults); // Expected: true
let ages2 = [17, 20, 25];
let allAdults2 = [Link](age => age >= 18);
[Link]("Are all ages >= 18 in ages2?", allAdults2);
// Expected: false (due to 17)
// Check if all tasks are completed
let tasks = [
{ id: 1, completed: true },
{ id: 2, completed: true },
{ id: 3, completed: false }
];
let allTasksCompleted = [Link](task => [Link]);
[Link]("Are all tasks completed?", allTasksCompleted);
// Expected: false
let allDoneTasks = [
{ id: 1, completed: true },
{ id: 2, completed: true }
];
let allTasksCompleted2 = [Link](task => [Link]);
[Link]("Are all tasks completed (all done)?", allTasksCompleted2);
// Expected: true
Exercise 47: Array Method: find() and findIndex()
// Exercise 47: Array Method: find() and findIndex()
let users = [
{ id: 1, name: "Alice", active: true },
{ id: 2, name: "Bob", active: false },
{ id: 3, name: "Charlie", active: true },
{ id: 4, name: "Alice", active: false } // Another Alice
];
// 1. Using find() to get the first matching element
let userWithId2 = [Link](user => [Link] === 2);
[Link]("User with ID 2:", userWithId2); // Expected: { id: 2, name: "Bob", active:
false }
let activeUser = [Link](user => [Link] === true);
Laurence Svekis Learn More [Link]
[Link]("First active user:", activeUser); // Expected: { id: 1, name: "Alice", active:
true }
// 2. Using findIndex() to get the index of the first matching element
let charlieIndex = [Link](user => [Link] === "Charlie");
[Link]("Index of Charlie:", charlieIndex); // Expected: 2
let firstAliceIndex = [Link](user => [Link] === "Alice");
[Link]("Index of first Alice:", firstAliceIndex);
// Expected: 0
// 3. Finding non-existent elements/indices
let nonExistentUser = [Link](user => [Link] === 99);
[Link]("Non-existent user:", nonExistentUser);
// Expected: undefined
let nonExistentIndex = [Link](user => [Link] === "David");
[Link]("Index of non-existent user:", nonExistentIndex);
// Expected: -1
Exercise 48: Set Data Structure
// Exercise 48: Set Data Structure
const uniqueNumbers = new Set();
[Link](1);
[Link](2);
[Link](3);
[Link](2); // Adding 2 again has no effect as Sets only store unique
values
[Link](4);
[Link](1);
// Adding 1 again has no effect
[Link]("Set after adding elements:", uniqueNumbers);
// Expected: Set { 1, 2, 3, 4 }
// 1. Size of the Set
[Link]("Size of Set:", [Link]);
// Expected: 4
// 2. Check for existence
[Link]("Does Set contain 3?", [Link](3));
// Expected: true
[Link]("Does Set contain 5?", [Link](5)); // Expected: false
// 3. Remove an element
Laurence Svekis Learn More [Link]
[Link](2);
[Link]("Set after deleting 2:", uniqueNumbers); // Expected: Set { 1, 3, 4 }
[Link]("Does Set contain 2 after deletion?", [Link](2));
// Expected: false
// 4. Iterate over the Set
[Link]("Elements in Set:");
for (let num of uniqueNumbers) {
[Link](num);
}
// Convert array with duplicates to array with unique elements using Set
let numbersWithDuplicates = [1, 5, 2, 8, 5, 1, 9, 2];
let uniqueArray = [...new Set(numbersWithDuplicates)]; // Convert to Set, then spread
back to array
[Link]("Unique array from duplicates:", uniqueArray);
// Expected: [1, 5, 2, 8, 9]
Exercise 49: Map Data Structure
// Exercise 49: Map Data Structure
const userRoles = new Map();
[Link]("Alice", "Admin");
[Link]("Bob", "Editor");
[Link]("Charlie", "Viewer");
[Link]("Map after adding elements:", userRoles);
// Expected: Map { 'Alice' => 'Admin', 'Bob' => 'Editor', 'Charlie' => 'Viewer' }
// 1. Get a value by key
[Link]("Role of Alice:", [Link]("Alice"));
// Expected: Admin
// 2. Check if a key exists
[Link]("Does David exist?", [Link]("David"));
// Expected: false
[Link]("Does Alice exist?", [Link]("Alice")); // Expected: true
// 3. Update a value
[Link]("Bob", "Moderator");
[Link]("Updated role of Bob:", [Link]("Bob")); // Expected: Moderator
// 4. Delete a key-value pair
[Link]("Charlie");
[Link]("Map after deleting Charlie:", userRoles);
Laurence Svekis Learn More [Link]
// Expected: Map { 'Alice' => 'Admin', 'Bob' => 'Moderator' }
// 5. Iterate over the Map
[Link]("\nIterating Map (entries):");
for (let [name, role] of userRoles) { // Directly destructure key and value
[Link](`${name}'s role is ${role}`);
}
[Link]("\nIterating Map (keys):");
for (let name of [Link]()) {
[Link](`User: ${name}`);
}
[Link]("\nIterating Map (values):");
for (let role of [Link]()) {
[Link](`Role: ${role}`);
}
Exercise 50: localStorage (Basic Persistence)
// Exercise 50: localStorage (Basic Persistence)
// Check if localStorage is available (it usually is in browsers)
if (typeof localStorage !== 'undefined') {
[Link]("localStorage is available.");
// 1. Store a string
[Link]("myUserName", "Sarah");
[Link]("Stored 'Sarah' in localStorage under 'myUserName'.");
// 2. Retrieve a string
let storedUserName = [Link]("myUserName");
[Link]("Retrieved 'myUserName':", storedUserName);
// Expected: Sarah
// 3. Store an object (must be stringified)
let settingsObject = {
theme: "dark",
notifications: true,
fontSize: 16
};
[Link]("userSettings", [Link](settingsObject));
[Link]("Stored settings object (stringified) under 'userSettings'.");
// 4. Retrieve and parse the object
let storedSettingsString = [Link]("userSettings");
Laurence Svekis Learn More [Link]
if (storedSettingsString) {
let parsedSettings = [Link](storedSettingsString);
[Link]("Retrieved and parsed 'userSettings':", parsedSettings);
// Expected: { theme: 'dark', notifications: true, fontSize: 16 }
[Link]("Theme from settings:", [Link]);
} else {
[Link]("No 'userSettings' found in localStorage.");
}
// 5. Remove an item
[Link]("myUserName");
[Link]("Removed 'myUserName' from localStorage.");
[Link]("Attempting to retrieve 'myUserName' after removal:",
[Link]("myUserName")); // Expected: null
// You can also clear all items (use with caution!)
// [Link]();
// [Link]("All localStorage cleared.");
} else {
[Link]("localStorage is not available in this environment.");
}
Exercise 51: Palindrome Checker
// Exercise 51: Palindrome Checker
function isPalindrome(str) {
// Step 1: Clean the string - convert to lowercase and remove non-alphanumeric
characters
const cleanedStr = [Link]().replace(/[^a-z0-9]/g, '');
// Step 2: Reverse the cleaned string
const reversedStr = [Link]('').reverse().join('');
// Step 3: Compare the cleaned string with its reversed version
return cleanedStr === reversedStr;
}
[Link]("'racecar' is a palindrome:", isPalindrome("racecar")); // Expected: true
[Link]("'hello' is a palindrome:", isPalindrome("hello"));
// Expected: false
[Link]("'Madam' is a palindrome:", isPalindrome("Madam")); // Expected: true
(case-insensitive)
[Link]("'A man, a plan, a canal: Panama' is a palindrome:", isPalindrome("A man,
Laurence Svekis Learn More [Link]
a plan, a canal: Panama"));
// Expected: true (ignores non-alphanumeric)
[Link]("'' is a palindrome:", isPalindrome(""));
// Expected: true (empty string is a palindrome)
[Link]("'A' is a palindrome:", isPalindrome("A"));
// Expected: true (single character is a palindrome)
Exercise 52: Anagram Checker
// Exercise 52: Anagram Checker
function cleanAndSortString(str) {
return str
.toLowerCase() // Convert to lowercase
.replace(/[^a-z0-9]/g, '') // Remove non-alphanumeric characters
.split('') // Split into an array of characters
.sort() // Sort the characters alphabetically
.join(''); // Join back into a string
}
function areAnagrams(str1, str2) {
// Anagrams must have the same length after cleaning
if ([Link] !== [Link]) {
return false;
}
return cleanAndSortString(str1) === cleanAndSortString(str2);
}
[Link]("'listen' and 'silent' are anagrams:", areAnagrams("listen", "silent"));
// Expected: true
[Link]("'Debit Card' and 'Bad Credit' are anagrams:", areAnagrams("Debit Card",
"Bad Credit"));
// Expected: true (ignores case and spaces)
[Link]("'hello' and 'world' are anagrams:", areAnagrams("hello", "world"));
// Expected: false
[Link]("'Anagram' and 'Nag A Ram' are anagrams:", areAnagrams("Anagram",
"Nag A Ram"));
// Expected: true
[Link]("'' and '' are anagrams:", areAnagrams("", "")); // Expected: true
[Link]("'a' and 'b' are anagrams:", areAnagrams("a", "b"));
// Expected: false
Laurence Svekis Learn More [Link]
Exercise 53: FizzBuzz
// Exercise 53: FizzBuzz
function fizzBuzz(countTo) {
[Link](`FizzBuzz up to ${countTo}:`);
for (let i = 1; i <= countTo; i++) {
let output = "";
if (i % 3 === 0) { // Check if divisible by 3
output += "Fizz";
}
if (i % 5 === 0) { // Check if divisible by 5
output += "Buzz";
}
// If output is empty, it means it's not divisible by 3 or 5
[Link](output || i);
// Use || to print number if output is empty
}
}
fizzBuzz(15);
// Will print up to 15 to demonstrate
Exercise 54: Remove Duplicates from an Array
// Exercise 54: Remove Duplicates from an Array
function removeDuplicates(arr) {
// The most concise and often preferred way using Set
return [...new Set(arr)];
}
// Alternative using filter and indexOf (less efficient for large arrays)
function removeDuplicatesLegacy(arr) {
return [Link]((item, index) => [Link](item) === index);
}
[Link]("Remove duplicates from [1, 2, 2, 3, 4, 4, 5]:", removeDuplicates([1, 2, 2, 3,
4, 4, 5]));
// Expected: [1, 2, 3, 4, 5]
[Link]("Remove duplicates from ['apple', 'banana', 'apple', 'orange']:",
Laurence Svekis Learn More [Link]
removeDuplicates(['apple', 'banana', 'apple', 'orange']));
// Expected: ['apple', 'banana', 'orange']
[Link]("Remove duplicates from [1, '1', 2, 1]:", removeDuplicates([1, '1', 2, 1]));
// Expected: [1, '1', 2] (Set distinguishes types)
[Link]("Remove duplicates from []:", removeDuplicates([]));
// Expected: []
[Link]("Remove duplicates from ['a', 'b', 'c']:", removeDuplicates(['a', 'b', 'c'])); //
Expected: ['a', 'b', 'c']
[Link]("\nUsing legacy method:");
[Link]("Remove duplicates from [1, 2, 2, 3, 4, 4, 5]:", removeDuplicatesLegacy([1,
2, 2, 3, 4, 4, 5]));
Exercise 55: Count Character Occurrences
// Exercise 55: Count Character Occurrences
function countChars(str) {
const charCounts = {};
// Initialize an empty object to store counts
const cleanedStr = [Link]();
// Convert to lowercase for case-insensitivity
for (let i = 0; i < [Link]; i++) {
const char = cleanedStr[i];
// Only count alphanumeric characters (optional, but good practice for practical
use)
if (/[a-z0-9]/.test(char)) {
// If the character is already a key in charCounts, increment its value
// Otherwise, add it as a new key with value 1
charCounts[char] = (charCounts[char] || 0) + 1;
}
}
return charCounts;
}
[Link]("Counts for 'hello world':", countChars("hello world"));
// Expected: { h: 1, e: 1, l: 3, o: 2, w: 1, r: 1, d: 1 } (excluding space)
[Link]("Counts for 'Programming is fun':", countChars("Programming is fun"));
// Expected: { p: 1, r: 2, o: 2, g: 2, a: 1, m: 2, i: 2, n: 2, s: 1, f: 1, u: 1 } (excluding space)
[Link]("Counts for 'AAAaaa':", countChars("AAAaaa"));
// Expected: { a: 6 }
Laurence Svekis Learn More [Link]
[Link]("Counts for '123123':", countChars("123123"));
// Expected: { '1': 2, '2': 2, '3': 2 }
Exercise 56: Merge Two Sorted Arrays
// Exercise 56: Merge Two Sorted Arrays
function mergeSortedArrays(arr1, arr2) {
const merged = [];
let ptr1 = 0; // Pointer for arr1
let ptr2 = 0;
// Pointer for arr2
// Compare elements from both arrays and add the smaller one to merged
while (ptr1 < [Link] && ptr2 < [Link]) {
if (arr1[ptr1] < arr2[ptr2]) {
[Link](arr1[ptr1]);
ptr1++;
} else {
[Link](arr2[ptr2]);
ptr2++;
}
}
// Add any remaining elements from arr1 (if any)
while (ptr1 < [Link]) {
[Link](arr1[ptr1]);
ptr1++;
}
// Add any remaining elements from arr2 (if any)
while (ptr2 < [Link]) {
[Link](arr2[ptr2]);
ptr2++;
}
return merged;
}
[Link]("Merge [1, 3, 5] and [2, 4, 6]:", mergeSortedArrays([1, 3, 5], [2, 4, 6]));
// Expected: [1, 2, 3, 4, 5, 6]
[Link]("Merge [10, 20] and [5, 15, 25]:", mergeSortedArrays([10, 20], [5, 15, 25]));
// Expected: [5, 10, 15, 20, 25]
[Link]("Merge [1, 2] and []:", mergeSortedArrays([1, 2], []));
Laurence Svekis Learn More [Link]
// Expected: [1, 2]
[Link]("Merge [] and [7, 8]:", mergeSortedArrays([], [7, 8]));
// Expected: [7, 8]
Exercise 57: Find Missing Number in a Sequence
// Exercise 57: Find Missing Number in a Sequence
function findMissingNumber(arr) {
const n = [Link] + 1;
// If one number is missing, n is (array length + 1)
// Calculate the expected sum of numbers from 1 to n
// Formula for sum of an arithmetic series: n * (n + 1) / 2
const expectedSum = n * (n + 1) / 2;
// Calculate the actual sum of numbers in the given array
let actualSum = 0;
for (let i = 0; i < [Link]; i++) {
actualSum += arr[i];
}
// Or using reduce: const actualSum = [Link]((sum, num) => sum + num, 0);
// The missing number is the difference between the expected and actual sums
return expectedSum - actualSum;
}
[Link]("Missing number in [1, 2, 4, 5]:", findMissingNumber([1, 2, 4, 5]));
// Expected: 3
[Link]("Missing number in [1, 3]:", findMissingNumber([1, 3]));
// Expected: 2 (n=3, sum=6, actual=4)
[Link]("Missing number in [2, 1, 4, 5, 6, 3, 8]:", findMissingNumber([2, 1, 4, 5, 6, 3,
8]));
// Expected: 7 (n=8, sum=36, actual=29)
[Link]("Missing number in [1]:", findMissingNumber([1]));
// Expected: undefined if array is empty (needs error handling)
[Link]("Missing number in []:", findMissingNumber([]));
// Expected: 1 (n=1, sum=1, actual=0)
Exercise 58: Flatten an Array
// Exercise 58: Flatten an Array
Laurence Svekis Learn More [Link]
function flattenArray(arr) {
let flatArr = [];
for (let i = 0; i < [Link]; i++) {
if ([Link](arr[i])) {
// If the element is an array, recursively flatten it and concatenate
flatArr = [Link](flattenArray(arr[i]));
} else {
// If it's not an array, just push it
[Link](arr[i]);
}
}
return flatArr;
}
// Modern ES2019+ built-in method for comparison
function flattenArrayBuiltIn(arr, depth = 1) {
return [Link](depth);
// flat() can take a depth argument, or Infinity
}
const nestedArray1 = [1, [2, 3], 4];
[Link]("Flatten [1, [2, 3], 4]:", flattenArray(nestedArray1)); // Expected: [1, 2, 3, 4]
const nestedArray2 = [1, [2, [3, 4]], 5, [6]];
[Link]("Flatten [1, [2, [3, 4]], 5, [6]]:", flattenArray(nestedArray2)); // Expected: [1,
2, 3, 4, 5, 6]
const nestedArray3 = [[1, 2], [3, [4, 5]]];
[Link]("Flatten [[1, 2], [3, [4, 5]]]:", flattenArray(nestedArray3)); // Expected: [1, 2,
3, 4, 5]
[Link]("\nUsing built-in flat() method:");
[Link]("Flatten [1, [2, 3], 4]:", flattenArrayBuiltIn(nestedArray1));
[Link]("Flatten [1, [2, [3, 4]], 5, [6]] (depth 1):", flattenArrayBuiltIn(nestedArray2,
1));
[Link]("Flatten [1, [2, [3, 4]], 5, [6]] (depth Infinity):",
flattenArrayBuiltIn(nestedArray2, Infinity));
Exercise 59: Implement a Simple Queue
// Exercise 59: Implement a Simple Queue
class Queue {
constructor() {
Laurence Svekis Learn More [Link]
[Link] = [];
// The array to store queue elements
}
// Add an element to the back of the queue
enqueue(element) {
[Link](element);
[Link](`Enqueued: ${element}. Queue: [${[Link](', ')}]`);
}
// Remove and return the element from the front of the queue
dequeue() {
if ([Link]()) {
[Link]("Queue is empty, cannot dequeue.");
return undefined;
}
const removedElement = [Link]();
// Removes from the beginning
[Link](`Dequeued: ${removedElement}. Queue: [${[Link](', ')}]`);
return removedElement;
}
// Return the element at the front of the queue without removing it
peek() {
if ([Link]()) {
[Link]("Queue is empty, nothing to peek.");
return undefined;
}
const frontElement = [Link][0];
[Link](`Peeked: ${frontElement}.`);
return frontElement;
}
// Check if the queue is empty
isEmpty() {
return [Link] === 0;
}
// Get the number of elements in the queue
size() {
return [Link];
}
// For debugging/display
printQueue() {
Laurence Svekis Learn More [Link]
[Link](`Current Queue: [${[Link](', ')}] (Size: ${[Link]()})`);
}
}
// Demonstrate Queue usage
const myQueue = new Queue();
[Link]("Is queue empty?", [Link]()); // Expected: true
[Link]("Task 1");
[Link]("Task 2");
[Link]("Task 3");
[Link]();
[Link]("Queue size:", [Link]()); // Expected: 3
[Link](); // Expected: Peeked: Task 1.
[Link]();
// Expected: Dequeued: Task 1. Queue: [Task 2, Task 3]
[Link](); // Expected: Peeked: Task 2.
[Link]();
// Expected: Dequeued: Task 2. Queue: [Task 3]
[Link](); // Expected: Dequeued: Task 3. Queue: []
[Link]();
// Expected: Queue is empty, cannot dequeue.
[Link]("Is queue empty?", [Link]());
// Expected: true
Exercise 60: Implement a Simple Stack
// Exercise 60: Implement a Simple Stack
class Stack {
constructor() {
[Link] = [];
// The array to store stack elements
}
// Add an element to the top of the stack
push(element) {
[Link](element);
[Link](`Pushed: ${element}. Stack: [${[Link](', ')}]`);
}
// Remove and return the element from the top of the stack
pop() {
Laurence Svekis Learn More [Link]
if ([Link]()) {
[Link]("Stack is empty, cannot pop.");
return undefined;
}
const poppedElement = [Link]();
// Removes from the end
[Link](`Popped: ${poppedElement}. Stack: [${[Link](', ')}]`);
return poppedElement;
}
// Return the element at the top of the stack without removing it
peek() {
if ([Link]()) {
[Link]("Stack is empty, nothing to peek.");
return undefined;
}
const topElement = [Link][[Link] - 1];
[Link](`Peeked: ${topElement}.`);
return topElement;
}
// Check if the stack is empty
isEmpty() {
return [Link] === 0;
}
// Get the number of elements in the stack
size() {
return [Link];
}
// For debugging/display
printStack() {
[Link](`Current Stack: [${[Link](', ')}] (Size: ${[Link]()})`);
}
}
// Demonstrate Stack usage
const myStack = new Stack();
[Link]("Is stack empty?", [Link]()); // Expected: true
[Link]("Page 1");
[Link]("Page 2");
[Link]("Page 3");
[Link]();
Laurence Svekis Learn More [Link]
[Link]("Stack size:", [Link]()); // Expected: 3
[Link](); // Expected: Peeked: Page 3.
[Link]();
// Expected: Popped: Page 3. Stack: [Page 1, Page 2]
[Link](); // Expected: Peeked: Page 2.
[Link]();
// Expected: Popped: Page 2. Stack: [Page 1]
[Link](); // Expected: Popped: Page 1. Stack: []
[Link]();
// Expected: Stack is empty, cannot pop.
[Link]("Is stack empty?", [Link]());
// Expected: true
Exercise 61: [Link]()
// Exercise 61: [Link]()
function fetchData(name, delay) {
return new Promise(resolve => {
setTimeout(() => {
[Link](`Finished fetching ${name} after ${delay}ms`);
resolve(`Data from ${name}`);
}, delay);
});
}
[Link]("Starting all data fetches...");
// Create an array of Promises
const allPromises = [
fetchData("Service A", 2000), // Longest delay
fetchData("Service B", 1000),
fetchData("Service C", 1500)
];
// Use [Link] to wait for all promises to resolve
[Link](allPromises)
.then(results => {
[Link]("\nAll data received:");
[Link](results); // Expected: ["Data from Service A", "Data from Service B",
"Data from Service C"]
})
Laurence Svekis Learn More [Link]
.catch(error => {
[Link]("One of the fetches failed:", error);
});
[Link]("Meanwhile, other tasks can run in the main thread.");
Exercise 62: Basic Event Loop Understanding with
setTimeout
// Exercise 62: Basic Event Loop Understanding with setTimeout
[Link]("1. Start of script.");
setTimeout(() => {
[Link]("3. Inside setTimeout callback (0ms delay).");
}, 0);
// Scheduled to run as soon as possible after call stack is clear
setTimeout(() => {
[Link]("4. Inside setTimeout callback (100ms delay).");
}, 100);
// Scheduled to run after at least 100ms
[Link]("2. End of script.");
// This loop simulates a long-running synchronous task
// It will block the main thread and prevent the 0ms timeout from executing
immediately
// even though its delay is 0ms.
let sum = 0;
for (let i = 0; i < 1000000000; i++) {
sum += i;
}
[Link]("5. Long synchronous task finished. Sum:", sum); // This will appear before
any timeouts
Exercise 63: Error Handling in async/await with
try...catch
// Exercise 63: Error Handling in async/await with try...catch
// Reusing the Promise-based function from Exercise 27/41
function fetchUserDataPromise(userId) {
return new Promise((resolve, reject) => {
Laurence Svekis Learn More [Link]
setTimeout(() => {
if (userId === 0 || userId < 0) { // Simulate error for 0 or negative IDs
reject(`Error: User with ID ${userId} not found or invalid.`);
return;
}
const user = {
id: userId,
name: `User ${userId}`,
status: "active"
};
resolve(user);
}, 800); // Shorter delay for demonstration
});
}
async function processUserData(userId) {
[Link](`\nAttempting to process data for user ID: ${userId}...`);
try {
const user = await fetchUserDataPromise(userId);
// Await the promise
[Link](`Success! Data for user ${userId}:`, user);
} catch (error) {
// If fetchUserDataPromise rejects, the error is caught here
[Link](`Failed to process data for user ID ${userId}:`, error);
} finally {
[Link](`Finished processing attempt for user ID: ${userId}.`);
}
}
// Demonstrate usage:
processUserData(10);
// Success case
processUserData(0); // Error case
processUserData(15); // Another success case
processUserData(-1);
// Another error case
Exercise 64: Generators (Basic)
// Exercise 64: Generators (Basic)
Laurence Svekis Learn More [Link]
function* idGenerator() {
let id = 1;
while (true) { // This loop will run indefinitely until the generator is stopped
yield id++;
// Pause execution and return the current 'id', then increment it for the next call
}
}
// Create a generator object
const myIdGenerator = idGenerator();
[Link]("Generated IDs:");
[Link]([Link]().value); // Expected: 1
[Link]([Link]().value); // Expected: 2
[Link]([Link]().value);
// Expected: 3
// You can create another independent generator
const anotherIdGenerator = idGenerator();
[Link]([Link]().value);
// Expected: 1 (starts fresh)
[Link]([Link]().value); // Expected: 4 (myIdGenerator continues)
Exercise 65: Iterators (Basic Custom)
// Exercise 65: Iterators (Basic Custom)
class MyRange {
constructor(from, to) {
[Link] = from;
[Link] = to;
}
// This method makes the object "iterable"
[[Link]]() {
let current = [Link];
// Keep track of the current number
// The iterator object must have a 'next' method
return {
next: () => {
if (current <= [Link]) {
// If there are more numbers, return the current one and advance
return { done: false, value: current++ };
Laurence Svekis Learn More [Link]
} else {
// If the range is exhausted, signal completion
return { done: true };
}
}
};
}
}
[Link]("Numbers in range 1 to 5:");
for (let num of new MyRange(1, 5)) {
[Link](num);
// Expected: 1, 2, 3, 4, 5
}
[Link]("\nNumbers in range 7 to 10:");
for (let num of new MyRange(7, 10)) {
[Link](num);
// Expected: 7, 8, 9, 10
}
Exercise 66: JavaScript Modules (Basic import/export)
// Exercise 66: JavaScript Modules (Basic import/export)
// --- content of [Link] ---
// export function capitalize(str) {
// if (!str) return '';
// return [Link](0).toUpperCase() + [Link](1).toLowerCase();
// }
// export const APP_NAME = "My Awesome App";
// export const PI_VALUE = 3.14159;
//
// Default export (only one per module)
// export default class Greeter {
// constructor(name) {
// [Link] = name;
// }
// sayHello() {
// [Link](`Hello, ${[Link]}!`);
// }
Laurence Svekis Learn More [Link]
// }
// --- content of [Link] ---
// import { capitalize, APP_NAME, PI_VALUE } from './[Link]';
// Named imports
// import MyGreeter from './[Link]'; // Default import (any name)
// [Link](`Application Name: ${APP_NAME}`);
// [Link](`Capitalized "hello": ${capitalize("hello")}`);
// [Link](`Value of PI: ${PI_VALUE}`);
// const greeterInstance = new MyGreeter("Module User");
// [Link]();
[Link]("This exercise describes modules conceptually.");
[Link]("See the commented-out code for example `[Link]` and `[Link]` file
structures.");
[Link]("\nTo run this in a browser, you'd use a script tag like:");
[Link]('<script type="module" src="[Link]"></script>');
[Link]("\nEach module runs in strict mode and has its own top-level scope.");
Exercise 67: Simple Event Emitter (Custom
Implementation)
// Exercise 67: Simple Event Emitter (Custom Implementation)
class EventEmitter {
constructor() {
[Link] = new Map();
// Stores event names as keys and arrays of listener functions as values
}
// Register a listener for a specific event
on(eventName, listener) {
if () {
[Link](eventName, []);
// If event doesn't exist, create an empty array for its listeners
}
[Link](eventName).push(listener);
// Add the listener to the array
[Link](`Registered listener for '${eventName}'.`);
}
// Emit an event, calling all registered listeners
emit(eventName, ...args) { // ...args allows passing any number of arguments to
Laurence Svekis Learn More [Link]
listeners
const eventListeners = [Link](eventName);
if (eventListeners) {
[Link](`Emitting event '${eventName}' with args: ${[Link](args)}`);
[Link](listener => {
try {
listener(...args); // Call each listener with the provided arguments
} catch (e) {
[Link](`Error in listener for '${eventName}':`, e);
}
});
} else {
[Link](`No listeners registered for '${eventName}'.`);
}
}
// Remove a specific listener for an event
off(eventName, listenerToRemove) {
const eventListeners = [Link](eventName);
if (eventListeners) {
const index = [Link](listenerToRemove);
if (index > -1) {
[Link](index, 1);
// Remove the listener from the array
[Link](`Unregistered listener for '${eventName}'.`);
} else {
[Link](`Listener not found for '${eventName}'.`);
}
} else {
[Link](`No listeners registered for '${eventName}'.`);
}
}
}
// Demonstrate usage
const myEmitter = new EventEmitter();
// Define some listener functions
const greetListener = (name) => [Link](`Hello, ${name}!`);
🎉
const logDataListener = (data) => [Link](`Received data: ${data}`);
const celebrateListener = (count, message) => [Link](` Celebrating ${count}
times: ${message}`); // Register listeners
Laurence Svekis Learn More [Link]
[Link]("greet", greetListener);
[Link]("dataLoaded", logDataListener);
[Link]("celebrate", celebrateListener);
[Link]("greet", (name) => [Link](`A secondary greeting to ${name}.`)); //
Multiple listeners for same event
// Emit events
[Link]("greet", "Alice");
[Link]("dataLoaded", { id: 101, status: "completed" });
[Link]("celebrate", 3, "New Milestone!");
[Link]("unknownEvent", "This won't do anything.");
// No listeners for this
// Unregister a listener
[Link]("greet", greetListener);
[Link]("greet", "Bob");
// greetListener won't be called now
[Link]("greet", greetListener); // Trying to remove again (should log "Listener
not found")
Exercise 68: WeakSet Data Structure
// Exercise 68: WeakSet Data Structure
// WeakSet can only store objects (not primitive values)
const weakSet = new WeakSet();
let user1 = { id: 1, name: "Alice" };
let user2 = { id: 2, name: "Bob" };
let user3 = { id: 3, name: "Charlie" }; // Add objects to the WeakSet
[Link](user1);
[Link](user2);
[Link](user3);
[Link]("WeakSet after adding objects.");
[Link]("WeakSet has user1:", [Link](user1)); // Expected: true
[Link]("WeakSet has user2:", [Link](user2));
// Expected: true
[Link]("WeakSet has user4 (non-existent):", [Link]({ id: 4 }));
// Expected: false (new object)
// Delete an object from WeakSet
[Link](user2);
[Link]("WeakSet has user2 after deletion:", [Link](user2));
Laurence Svekis Learn More [Link]
// Expected: false
// What happens if an object is no longer referenced elsewhere?
// Let's remove the strong reference to user3
user3 = null;
// user3 is now eligible for garbage collection
// The WeakSet will automatically remove user3 if it's garbage collected.
// However, we cannot directly observe this or iterate the WeakSet to prove it.
// The `has` method might still return true for a short while if GC hasn't run.
// There is no .size property or iteration methods on WeakSet.
// A common use case: keeping track of objects that have certain permissions or
states,
// without preventing them from being garbage collected if they are no longer used
elsewhere.
class Permissions {
constructor() {
[Link] = new WeakSet();
}
grantAdmin(userObj) {
[Link](userObj);
}
isAdmin(userObj) {
return [Link](userObj);
}
}
const permSystem = new Permissions();
let currentUser = { id: 10, name: "AdminUser" };
[Link](currentUser);
[Link]("Is currentUser an admin?", [Link](currentUser));
// Expected: true
currentUser = null; // AdminUser object becomes eligible for GC
// At some point later, it will be automatically removed from [Link]
// without us having to explicitly delete it.
Exercise 69: WeakMap Data Structure
// Exercise 69: WeakMap Data Structure
// WeakMap can only use objects as keys (not primitive values)
const weakMap = new WeakMap();
Laurence Svekis Learn More [Link]
let obj1 = { name: "Config A" };
let obj2 = { name: "User Session" };
let obj3 = { name: "DOM Element Ref" }; // Set key-value pairs
[Link](obj1, { version: 1.0, active: true });
[Link](obj2, { sessionId: "xyz123", lastAccess: new Date() });
[Link](obj3, "This is data for the DOM element");
[Link]("WeakMap after setting entries.");
[Link]("Data for obj1:", [Link](obj1)); // Expected: { version: 1, active: true }
[Link]("WeakMap has obj2:", [Link](obj2));
// Expected: true
[Link]("Data for obj3:", [Link](obj3)); // Expected: This is data for the
DOM element
// Delete an entry
[Link](obj1);
[Link]("Data for obj1 after deletion:", [Link](obj1)); // Expected: undefined
// What happens if a key object is no longer referenced elsewhere?
obj2 = null; // obj2 (the key) is now eligible for garbage collection
// If obj2 is garbage collected, its entry in weakMap will also be automatically removed.
// Like WeakSet, WeakMap has no .size property and cannot be iterated.
// We cannot directly observe the entry's removal until GC runs.
// A common use case: associating private data with objects
const privateData = new WeakMap();
class User {
constructor(name, initialPrivateInfo) {
[Link] = name;
[Link](this, initialPrivateInfo);
// Store private data in WeakMap using 'this' as key
}
getPrivateInfo() {
return [Link](this);
}
updatePrivateInfo(newInfo) {
[Link](this, newInfo);
}
}
let user = new User("Jane Doe", { secretId: "abc", role: "admin" });
[Link]("User private info:", [Link]());
[Link]({ secretId: "def", role: "guest" });
[Link]("User updated private info:", [Link]());
Laurence Svekis Learn More [Link]
user = null;
// User object is now eligible for GC, and its associated private data in WeakMap will
also be removed.
Exercise 70: Set for Counting Unique Elements
(Advanced)
// Exercise 70: Set for Counting Unique Elements (Advanced)
function countUniqueElements(arr) {
const uniqueItems = new Set(arr);
// Create a Set from the array, automatically handling uniqueness
return [Link];
// The size property of the Set gives the count of unique elements
}
[Link]("Unique count in [1, 2, 2, 3, 4, 4, 5]:", countUniqueElements([1, 2, 2, 3, 4, 4,
5]));
// Expected: 5
[Link]("Unique count in ['apple', 'banana', 'apple', 'orange']:",
countUniqueElements(['apple', 'banana', 'apple', 'orange']));
// Expected: 3
[Link]("Unique count in []:", countUniqueElements([])); // Expected: 0
[Link]("Unique count in [1, 1, 1, 1]:", countUniqueElements([1, 1, 1, 1]));
// Expected: 1
[Link]("Unique count in [1, '1', 2]:", countUniqueElements([1, '1', 2]));
// Expected: 3 (Set distinguishes number 1 from string '1')
Exercise 71: Selecting Elements by ID
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 71</title>
</head>
<body>
<p id="myParagraph">This is the original paragraph text.</p>
Laurence Svekis Learn More [Link]
<script>
[Link]('DOMContentLoaded', () => {
// 1. Select the paragraph element by its ID
const paragraph = [Link]('myParagraph');
// 2. Check if the element exists before trying to modify it
if (paragraph) {
// 3. Change its text content
[Link] = "Hello from JavaScript! The ID selector worked.";
[Link]("Paragraph text changed successfully!");
} else {
[Link]("Element with ID 'myParagraph' not found!");
}
});
[Link]("Run this code in an HTML file to see the DOM manipulation.");
</script>
</body>
</html>
Exercise 72: Selecting Elements by Class Name
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 72</title>
</head>
<body>
<ul>
<li class="listItem">First Original Item</li>
<li class="listItem">Second Original Item</li>
<li class="listItem">Third Original Item</li>
</ul>
<script>
[Link]('DOMContentLoaded', () => {
// 1. Select all elements with the class 'listItem'
Laurence Svekis Learn More [Link]
const listItems = [Link]('listItem');
[Link](`Found ${[Link]} elements with class 'listItem'.`);
// 2. Iterate through the HTMLCollection (which is array-like, not a true array)
for (let i = 0; i < [Link]; i++) {
listItems[i].textContent = `Item ${i + 1} - Updated by JS`;
}
// Alternative for iteration (converting to Array):
// [Link](listItems).forEach((item, index) => {
// [Link] = `Item ${index + 1} - Updated by JS (using forEach)`;
// });
[Link]("List item texts changed successfully!");
});
[Link]("Run this code in an HTML file to see the DOM manipulation.");
</script>
</body>
</html>
Exercise 73: Selecting Elements with querySelector
and querySelectorAll
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 73</title>
<style>
#container {
border: 1px solid #ccc;
padding: 15px;
margin: 20px;
border-radius: 8px;
background-color: #f9f9f9;
}
p {
margin-bottom: 10px;
}
</style>
Laurence Svekis Learn More [Link]
</head>
<body>
<div id="container">
<h3>Container Content</h3>
<p class="intro">This is the introductory paragraph within the container.</p>
<p>First general paragraph.</p>
<p>Second general paragraph.</p>
<span class="intro">This span also has intro class, but shouldn't be selected by
'[Link]'</span>
</div>
<script>
[Link]('DOMContentLoaded', () => {
// 1. Select the first element that matches the CSS selector
const introParagraph = [Link]('#container .intro');
if (introParagraph) {
[Link] = "The intro paragraph has been updated!";
[Link] = "blue";
[Link]("Intro paragraph updated using querySelector.");
} else {
[Link]("Intro paragraph not found!");
}
// 2. Select all elements that match the CSS selector
const allParagraphs = [Link]('#container p');
[Link](`Found ${[Link]} paragraphs inside container.`);
// 3. Iterate through the NodeList (which behaves like an Array for iteration)
[Link]((p, index) => {
[Link] = (index % 2 === 0) ? '#e0ffe0' : '#f0fff0'; //
Alternate background
[Link] = '5px';
[Link] = '5px';
[Link] = '5px';
[Link] = '1px solid #ccc';
});
[Link]("All paragraphs inside container styled using querySelectorAll.");
});
[Link]("Run this code in an HTML file to see the DOM manipulation.");
</script>
</body>
Laurence Svekis Learn More [Link]
</html>
Exercise 74: Modifying Element Attributes
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 74</title>
</head>
<body>
<img id="myImage"
src="[Link] alt="An original
placeholder image."
style="border: 2px solid grey; margin: 10px;">
<script>
[Link]('DOMContentLoaded', () => {
const myImage = [Link]('myImage');
if (myImage) {
[Link]("Original Image Src:", [Link]('src'));
[Link]("Original Image Alt:", [Link]('alt'));
// 1. Change its src attribute
[Link]('src',
'[Link]
[Link]("Image src changed.");
// 2. Change its alt attribute
[Link]('alt', 'A descriptive new image for the placeholder.');
[Link]("Image alt changed.");
// 3. Add a title attribute
[Link]('title', 'Hover to see title! Click me!');
[Link]("Image title added.");
// 4. Remove the alt attribute after 2 seconds
setTimeout(() => {
[Link]('alt');
[Link]("Image alt attribute removed after 2 seconds.");
[Link]("Current Image Alt (after removal):",
Laurence Svekis Learn More [Link]
[Link]('alt'));
// Will be null
}, 2000);
} else {
[Link]("Element with ID 'myImage' not found!");
}
});
[Link]("Run this code in an HTML file to see the DOM manipulation.");
</script>
</body>
</html>
Exercise 75: Adding and Removing CSS Classes
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 75</title>
<style>
#myBox {
width: 150px;
height: 150px;
background-color: lightgrey;
margin: 20px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2em;
transition: background-color 0.3s ease, border 0.3s ease;
border: 2px solid transparent;
border-radius: 8px;
}
.highlight {
background-color: #ffd700; /* Gold */
border-color: #da0037; /* Dark Red */
box-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
Laurence Svekis Learn More [Link]
}
/* Basic styling for buttons (optional, can use Tailwind/Bootstrap) */
button {
padding: 8px 15px;
margin: 5px;
border: none;
border-radius: 5px;
cursor: pointer;
color: white;
font-weight: bold;
}
#addHighlightBtn { background-color: #4CAF50; } /* Green */
#removeHighlightBtn { background-color: #f44336; } /* Red */
#toggleHighlightBtn { background-color: #008CBA; } /* Blue */
</style>
</head>
<body>
<button id="addHighlightBtn">Add Highlight</button>
<button id="removeHighlightBtn">Remove Highlight</button>
<button id="toggleHighlightBtn">Toggle Highlight</button>
<div id="myBox">Interactive Box</div>
<script>
[Link]('DOMContentLoaded', () => {
const myBox = [Link]('myBox');
const addBtn = [Link]('addHighlightBtn');
const removeBtn = [Link]('removeHighlightBtn');
const toggleBtn = [Link]('toggleHighlightBtn');
if (myBox && addBtn && removeBtn && toggleBtn) {
[Link]('click', () => {
[Link]('highlight');
[Link]("Class 'highlight' added.");
});
[Link]('click', () => {
[Link]('highlight');
[Link]("Class 'highlight' removed.");
});
[Link]('click', () => {
Laurence Svekis Learn More [Link]
[Link]('highlight');
[Link]("Class 'highlight' toggled.");
});
} else {
[Link]("One or more elements not found!");
}
});
[Link]("Run this code in an HTML file to see the DOM manipulation.");
</script>
</body>
</html>
Exercise 76: Creating and Appending Elements
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 76</title>
<style>
#outputContainer {
border: 1px dashed grey;
padding: 10px;
margin-top: 20px;
border-radius: 5px;
background-color: #f8f8f8;
}
</style>
</head>
<body>
<div id="outputContainer">
<h3>Content will be added below:</h3>
</div>
<script>
[Link]('DOMContentLoaded', () => {
const outputContainer = [Link]('outputContainer');
Laurence Svekis Learn More [Link]
if (outputContainer) {
// 1. Create a new <h2> element
const newHeading = [Link]('h2');
[Link] = "Dynamically Created Heading";
[Link] = "#2c3e50";
[Link] = "10px";
// 2. Create a new paragraph element
const newParagraph = [Link]('p');
[Link] = "This paragraph was proudly added by
JavaScript!";
[Link] = "italic";
[Link] = "#34495e";
[Link] = "10px";
// 3. Append both new elements to the outputContainer
[Link](newHeading);
[Link](newParagraph);
[Link]("New elements created and appended to outputContainer.");
// Create and append a button that adds more content
const addButton = [Link]('button');
[Link] = "Add More Content";
[Link] = "bg-purple-600 text-white p-2 rounded-md mt-4";
/* Example class, for visual */
[Link](addButton);
let clickCount = 0;
[Link]('click', () => {
clickCount++;
const dynamicPara = [Link]('p');
[Link] = `You clicked the button! This is dynamic
content #${clickCount}.`;
[Link] = '#f0f4f8';
[Link] = '5px';
[Link] = '4px';
[Link] = '5px';
[Link](dynamicPara, addButton); // Insert before
the button
});
} else {
Laurence Svekis Learn More [Link]
[Link]("Element with ID 'outputContainer' not found!");
}
});
[Link]("Run this code in an HTML file to see the DOM manipulation.");
</script>
</body>
</html>
Exercise 77: Basic Event Listener (click)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 77</title>
</head>
<body>
<button id="myButton">Click Me</button>
<p id="clickCountDisplay" style="margin-top: 10px; font-size: 1.2em;">Clicks: 0</p>
<script>
[Link]('DOMContentLoaded', () => {
const myButton = [Link]('myButton');
const clickCountDisplay = [Link]('clickCountDisplay');
let clickCount = 0;
if (myButton && clickCountDisplay) {
// Add a click event listener to the button
[Link]('click', () => {
clickCount++;
[Link]("Button clicked! Total clicks:", clickCount);
[Link] = `Clicks: ${clickCount}`;
// Add a temporary visual feedback
[Link] = 'scale(0.98)';
setTimeout(() => {
[Link] = 'scale(1)';
}, 100);
Laurence Svekis Learn More [Link]
});
} else {
[Link]("Button or display element not found!");
}
});
[Link]("Run this code in an HTML file and click the button to see console
output.");
</script>
</body>
</html>
Exercise 78: Input Event Listener (input)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 78</title>
<style>
input[type="text"] {
padding: 8px;
width: 250px;
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 10px;
}
#displayArea {
font-size: 1.1em;
color: #333;
}
</style>
</head>
<body>
<div>
<label for="myInput">Type something:</label><br>
<input type="text" id="myInput">
<p id="displayArea">You typed: <span style="font-weight: bold; color:
Laurence Svekis Learn More [Link]
blue;"></span></p>
</div>
<script>
[Link]('DOMContentLoaded', () => {
const myInput = [Link]('myInput');
const displayArea = [Link]('displayArea');
const typedTextSpan = displayArea ? [Link]('span') : null; //
Span to update
if (myInput && displayArea && typedTextSpan) {
// Add an 'input' event listener to the input field
[Link]('input', (event) => {
// [Link] refers to the element that triggered the event (the input
field)
// [Link] gives the current value of the input field
[Link] = [Link];
[Link]("Input value:", [Link]);
});
} else {
[Link]("Input or display elements not found!");
}
});
[Link]("Run this code in an HTML file and type into the input field to see live
updates.");
</script>
</body>
</html>
Exercise 79: fetch API (Simple GET Request)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 79</title>
</head>
Laurence Svekis Learn More [Link]
<body>
<h1>Fetch API Example</h1>
<p>Check the browser's console for the fetched data.</p>
<script>
// A public API endpoint to fetch data from
const API_URL = '[Link]
const INVALID_API_URL = '[Link]
// To demonstrate error
async function fetchAndDisplayPost(url) {
[Link](`\nAttempting to fetch data from: ${url}`);
try {
const response = await fetch(url);
// Initiate the fetch request
// Check if the request was successful (status code 200-299)
if (![Link]) {
// If not successful, throw an error with the status text
throw new Error(`HTTP error! Status: ${[Link]} -
${[Link]}`);
}
const data = await [Link]();
// Parse the response body as JSON
[Link]("Successfully fetched data:");
[Link](data);
// Log the parsed JSON data
} catch (error) {
// Catch any network errors or errors thrown from the [Link] check
[Link]("Error fetching data:", [Link]);
}
}
// Call the function to fetch data
fetchAndDisplayPost(API_URL);
fetchAndDisplayPost(INVALID_API_URL);
// To demonstrate error handling
Laurence Svekis Learn More [Link]
[Link]("This message will appear before the fetch results, demonstrating
asynchronicity.");
</script>
</body>
</html>
Exercise 80: Basic Animation with setInterval
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercise 80</title>
<style>
#animatedBox {
width: 60px;
height: 60px;
background-color: #28a745; /* Green */
border-radius: 8px;
position: relative; /* Essential for 'left' property to work */
left: 0px;
top: 10px;
transition: background-color 0.3s ease;
}
.controls {
margin-top: 20px;
}
.control-btn {
padding: 8px 16px;
border-radius: 6px;
font-size: 1em;
cursor: pointer;
border: none;
margin-right: 10px;
transition: background-color 0.2s ease;
}
Laurence Svekis Learn More [Link]
.start-btn { background-color: #007bff; color: white; }
.start-btn:hover { background-color: #0056b3; }
.stop-btn { background-color: #dc3545; color: white; }
.stop-btn:hover { background-color: #b02a3a; }
</style>
</head>
<body>
<div id="animatedBox"></div>
<div class="controls">
<button id="startButton" class="control-btn start-btn">Start Animation</button>
<button id="stopButton" class="control-btn stop-btn">Stop Animation</button>
</div>
<script>
[Link]('DOMContentLoaded', () => {
const animatedBox = [Link]('animatedBox');
const startButton = [Link]('startButton');
const stopButton = [Link]('stopButton');
let position = 0;
let animationIntervalId;
const speed = 2; // Pixels per interval
const maxPosition = [Link] - 80; // Stop before going off screen
(adjust for box width)
const intervalDelay = 10; // Milliseconds per update
function animateBox() {
if (animatedBox) {
animationIntervalId = setInterval(() => {
position += speed;
if (position > maxPosition) {
position = 0; // Reset to start
}
[Link] = position + 'px';
}, intervalDelay);
[Link]("Animation started.");
} else {
[Link]("Animated box not found!");
}
Laurence Svekis Learn More [Link]
}
function stopAnimation() {
if (animationIntervalId) {
clearInterval(animationIntervalId);
animationIntervalId = null;
[Link]("Animation stopped.");
}
}
if (startButton && stopButton) {
[Link]('click', () => {
if (!animationIntervalId) { // Prevent starting multiple intervals
animateBox();
}
});
[Link]('click', stopAnimation);
// Optional: Stop animation if window resizes to recalculate maxPosition
[Link]('resize', stopAnimation);
} else {
[Link]("Animation control buttons not found!");
}
});
[Link]("Run this code in an HTML file to see the animation.");
</script>
</body>
</html>
Exercise 81: Binary Search
// Exercise 81: Binary Search
function binarySearch(arr, target) {
let left = 0;
let right = [Link] - 1;
while (left <= right) {
const mid = [Link]((left + right) / 2);
// Calculate the middle index
// Check if the middle element is the target
Laurence Svekis Learn More [Link]
if (arr[mid] === target) {
return mid;
// Target found
}
// If the target is greater, ignore the left half
if (arr[mid] < target) {
left = mid + 1;
}
// If the target is smaller, ignore the right half
else {
right = mid - 1;
}
}
return -1; // Target not found in the array
}
const sortedArray = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91];
[Link]("Index of 12:", binarySearch(sortedArray, 12)); // Expected: 3
[Link]("Index of 23:", binarySearch(sortedArray, 23));
// Expected: 5
[Link]("Index of 2:", binarySearch(sortedArray, 2)); // Expected: 0
[Link]("Index of 91:", binarySearch(sortedArray, 91));
// Expected: 9
[Link]("Index of 7:", binarySearch(sortedArray, 7)); // Expected: -1 (not found)
[Link]("Index of 100:", binarySearch(sortedArray, 100));
// Expected: -1 (not found)
[Link]("Index of 38:", binarySearch(sortedArray, 38));
// Expected: 6
Exercise 82: Bubble Sort
// Exercise 82: Bubble Sort
function bubbleSort(arr) {
const n = [Link];
let swapped; // Flag to optimize: if no swaps in an pass, array is sorted
// Outer loop: iterate through the array from the beginning
// After each pass, the largest unsorted element "bubbles" to its correct position at
the end
for (let i = 0; i < n - 1; i++) {
Laurence Svekis Learn More [Link]
swapped = false;
// Reset flag for each pass
// Inner loop: compare adjacent elements and swap if they are in the wrong order
// The last 'i' elements are already in place, so we don't need to check them
for (let j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// Swap arr[j] and arr[j + 1]
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // ES6 array destructuring for swapping
swapped = true;
// A swap occurred in this pass
}
}
// Optimization: If no two elements were swapped by inner loop, then array is sorted
if (!swapped) {
break;
}
}
return arr; // Return the sorted array
}
const unsortedArray1 = [64, 34, 25, 12, 22, 11, 90];
[Link]("Bubble Sort [64, 34, 25, 12, 22, 11, 90]:", bubbleSort([...unsortedArray1]));
// Use spread to avoid mutating original
const unsortedArray2 = [5, 1, 4, 2, 8];
[Link]("Bubble Sort [5, 1, 4, 2, 8]:", bubbleSort([...unsortedArray2]));
const unsortedArray3 = [1, 2, 3, 4, 5];
// Already sorted
[Link]("Bubble Sort [1, 2, 3, 4, 5]:", bubbleSort([...unsortedArray3]));
const unsortedArray4 = [9, 8, 7, 6, 5];
// Reverse sorted
[Link]("Bubble Sort [9, 8, 7, 6, 5]:", bubbleSort([...unsortedArray4]));
Exercise 83: Selection Sort
// Exercise 83: Selection Sort
function selectionSort(arr) {
const n = [Link];
// Outer loop: iterate through the array
for (let i = 0; i < n - 1; i++) {
Laurence Svekis Learn More [Link]
// Assume the current element is the minimum
let minIndex = i;
// Inner loop: find the smallest element in the unsorted portion
for (let j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
// Update minIndex if a smaller element is found
}
}
// If the smallest element is not at the current position 'i', swap them
if (minIndex !== i) {
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
// ES6 swap
}
}
return arr;
// Return the sorted array
}
const unsortedArray1 = [64, 25, 12, 22, 11];
[Link]("Selection Sort [64, 25, 12, 22, 11]:", selectionSort([...unsortedArray1]));
const unsortedArray2 = [5, 1, 4, 2, 8];
[Link]("Selection Sort [5, 1, 4, 2, 8]:", selectionSort([...unsortedArray2]));
const unsortedArray3 = [1, 2, 3, 4, 5];
// Already sorted
[Link]("Selection Sort [1, 2, 3, 4, 5]:", selectionSort([...unsortedArray3]));
Exercise 84: Insertion Sort
// Exercise 84: Insertion Sort
function insertionSort(arr) {
const n = [Link];
// Start from the second element (index 1) because the first element (index 0)
// is considered the "sorted" part initially.
for (let i = 1; i < n; i++) {
let current = arr[i];
// The element to be inserted into the sorted portion
let j = i - 1;
// Pointer to the last element of the sorted portion
Laurence Svekis Learn More [Link]
// Move elements of arr[0..i-1], that are greater than current,
// to one position ahead of their current position
while (j >= 0 && arr[j] > current) {
arr[j + 1] = arr[j];
// Shift element to the right
j--;
}
// Place current element at its correct position in the sorted part
arr[j + 1] = current;
}
return arr; // Return the sorted array
}
const unsortedArray1 = [12, 11, 13, 5, 6];
[Link]("Insertion Sort [12, 11, 13, 5, 6]:", insertionSort([...unsortedArray1]));
const unsortedArray2 = [5, 1, 4, 2, 8];
[Link]("Insertion Sort [5, 1, 4, 2, 8]:", insertionSort([...unsortedArray2]));
const unsortedArray3 = [1, 2, 3, 4, 5];
// Already sorted (best case)
[Link]("Insertion Sort [1, 2, 3, 4, 5]:", insertionSort([...unsortedArray3]));
const unsortedArray4 = [9, 8, 7, 6, 5]; // Reverse sorted (worst case)
[Link]("Insertion Sort [9, 8, 7, 6, 5]:", insertionSort([...unsortedArray4]));
Exercise 85: Memoization (Simple Factorial)
// Exercise 85: Memoization (Simple Factorial)
// Using a Map for cache for better key flexibility (though object keys work for
numbers)
const factorialCache = new Map();
function memoizedFactorial(n) {
// Base case for recursion
if (n === 0 || n === 1) {
return 1;
}
// Check if the result is already in the cache
if ([Link](n)) {
[Link](`Getting factorial(${n}) from cache.`);
return [Link](n);
}
Laurence Svekis Learn More [Link]
// If not in cache, compute the result recursively
[Link](`Computing factorial(${n})...`);
const result = n * memoizedFactorial(n - 1);
// Store the computed result in the cache before returning
[Link](n, result);
return result;
}
[Link]("--- First set of calls ---");
[Link]("Factorial(5):", memoizedFactorial(5)); // Will compute 5!, 4!, 3!, 2!, 1!, 0!
[Link]("\n--- Second set of calls (demonstrating caching) ---");
[Link]("Factorial(3):", memoizedFactorial(3)); // Should use cache for 3!, 2!, 1!, 0!
[Link]("Factorial(6):", memoizedFactorial(6)); // Will compute 6!, then use cache
for 5! and below
[Link]("Factorial(5):", memoizedFactorial(5));
// Should use cache directly
Exercise 86: Simple Debounce Function
// Exercise 86: Simple Debounce Function
function debounce(func, delay) {
let timeoutId;
// This variable will store the timer ID across calls
// Return a new function (the debounced version)
return function(...args) { // ...args captures all arguments passed to the debounced
function
const context = this;
// Capture the 'this' context of the call
// Clear any existing timer.
// If the debounced function is called again before the delay
// elapses, the previous timer is cancelled, and a new one is set.
clearTimeout(timeoutId);
// Set a new timer
timeoutId = setTimeout(() => {
// Execute the original function after the delay
// Use .apply to correctly pass 'this' context and arguments
[Link](context, args);
}, delay);
};
Laurence Svekis Learn More [Link]
}
// Example Usage: Simulate a search input
function performSearch(query) {
[Link](`Performing search for: "${query}"...`);
}
// Create a debounced version of performSearch with a 500ms delay
const debouncedSearch = debounce(performSearch, 500);
[Link]("Simulating rapid typing in a search bar...");
debouncedSearch("a");
debouncedSearch("ap");
debouncedSearch("app");
setTimeout(() => debouncedSearch("appl"), 100);
setTimeout(() => debouncedSearch("apple"), 200);
// This will be the only one that triggers performSearch
setTimeout(() => [Link]("--- Finished typing simulation ---"), 1000);
// Another example: Button click that only triggers once
let clickCount = 0;
function handleClick() {
clickCount++;
[Link](`Button clicked! (Actual click count: ${clickCount})`);
}
const debouncedClick = debounce(handleClick, 1000);
[Link]("\nSimulating rapid button clicks...");
debouncedClick(); // Calls debounce, sets timer
setTimeout(debouncedClick, 100); // Clears previous, sets new timer
setTimeout(debouncedClick, 200);
// Clears previous, sets new timer
setTimeout(debouncedClick, 300); // Clears previous, sets new timer
// After 1000ms from the LAST call (at 300ms), handleClick will fire once.
setTimeout(() => [Link]("--- Finished click simulation ---"), 1500);
Exercise 87: Simple Throttling Function
// Exercise 87: Simple Throttling Function
function throttle(func, delay) {
let inThrottle;
// Flag to indicate if we are currently in a throttled state
let lastFn;
Laurence Svekis Learn More [Link]
// Stores a reference to the setTimeout callback
let lastTime;
// Stores the timestamp of the last execution
// Return a new function (the throttled version)
return function(...args) {
const context = this;
// If not currently throttled, execute immediately
if (!inThrottle) {
[Link](context, args);
lastTime = [Link]();
inThrottle = true; // Enter throttled state
} else {
// If currently throttled, clear any pending execution
clearTimeout(lastFn);
// Schedule a new execution after the remaining delay has passed
// [Link] ensures the delay is at least 0, preventing negative delays
lastFn = setTimeout(() => {
// Check if enough time has passed since the last execution
if (([Link]() - lastTime) >= delay) {
[Link](context, args);
lastTime = [Link]();
inThrottle = false; // Exit throttled state (important for subsequent immediate
executions)
}
}, [Link](delay - ([Link]() - lastTime), 0));
}
};
}
// Example Usage: Simulate a scroll event
function handleScroll(event) {
[Link](`Scrolling detected! Timestamp: ${new Date().toLocaleTimeString()}`);
// In a real scenario, you'd do DOM updates here, e.g., update scroll position display
}
// Create a throttled version of handleScroll with a 1000ms (1 second) delay
const throttledScroll = throttle(handleScroll, 1000);
[Link]("Simulating rapid scroll events (will only log every 1 second)...");
throttledScroll(); // Should trigger immediately
setTimeout(throttledScroll, 100);
setTimeout(throttledScroll, 200);
Laurence Svekis Learn More [Link]
setTimeout(throttledScroll, 300);
setTimeout(throttledScroll, 1050); // Should trigger after 1 sec
setTimeout(throttledScroll, 1100);
setTimeout(throttledScroll, 2200);
// Should trigger again after another 1 sec from previous
setTimeout(() => [Link]("--- Finished scroll simulation ---"), 3000);
Exercise 88: Linked List (Basic Implementation)
// Exercise 88: Linked List (Basic Implementation)
// Represents a single node in the linked list
class Node {
constructor(value) {
[Link] = value;
[Link] = null; // Pointer to the next node
}
}
// Manages the linked list
class LinkedList {
constructor() {
[Link] = null;
// The first node in the list
[Link] = null;
// The last node in the list
[Link] = 0;
// Number of elements in the list
}
// Adds a new node to the end of the list
add(value) {
const newNode = new Node(value);
if (![Link]) {
// If the list is empty, the new node is both the head and the tail
[Link] = newNode;
[Link] = newNode;
} else {
// Otherwise, append the new node to the end and update the tail
[Link] = newNode;
[Link] = newNode;
Laurence Svekis Learn More [Link]
}
[Link]++;
[Link](`Added "${value}". Current size: ${[Link]}`);
}
// Prints all values in the list
print() {
if (![Link]) {
[Link]("Linked List is empty.");
return;
}
let current = [Link];
let result = [];
while (current) {
[Link]([Link]);
current = [Link];
// Move to the next node
}
[Link](`Linked List: ${[Link](" -> ")}`);
}
// Finds if a value exists in the list
find(value) {
if (![Link]) {
return false;
}
let current = [Link];
while (current) {
if ([Link] === value) {
return true;
// Value found
}
current = [Link];
}
return false; // Value not found
}
// Removes the first occurrence of a value
remove(value) {
if (![Link]) {
[Link]("Cannot remove: List is empty.");
return false;
Laurence Svekis Learn More [Link]
}
// If the head needs to be removed
if ([Link] === value) {
[Link] = [Link];
if (![Link]) { // If list becomes empty
[Link] = null;
}
[Link]--;
[Link](`Removed "${value}". Current size: ${[Link]}`);
return true;
}
let current = [Link];
while ([Link] && [Link] !== value) {
current = [Link];
}
if ([Link]) { // Found the node to remove
if ([Link] === [Link]) { // If removing the tail
[Link] = current;
}
[Link] = [Link];
[Link]--;
[Link](`Removed "${value}". Current size: ${[Link]}`);
return true;
}
[Link](`"${value}" not found for removal.`);
return false;
}
}
// Demonstrate Linked List usage
const myList = new LinkedList();
[Link](); // Expected: Linked List is empty.
[Link]("A");
[Link]("B");
[Link]("C");
[Link](); // Expected: Linked List: A -> B -> C
[Link]("Does 'B' exist?", [Link]("B"));
// Expected: true
[Link]("Does 'D' exist?", [Link]("D")); // Expected: false
[Link]("B"); // Expected: Removed "B". Current size: 2
Laurence Svekis Learn More [Link]
[Link]();
// Expected: Linked List: A -> C
[Link]("A"); // Expected: Removed "A". Current size: 1
[Link]();
// Expected: Linked List: C
[Link]("C"); // Expected: Removed "C". Current size: 0
[Link](); // Expected: Linked List is empty.
[Link]("X"); // Expected: Cannot remove: List is empty.
Exercise 89: Tree Traversal (Depth-First Search -
Preorder)
// Exercise 89: Tree Traversal (Depth-First Search - Preorder)
// Represents a single node in the binary tree
class TreeNode {
constructor(value) {
[Link] = value;
[Link] = null; // Pointer to the left child node
[Link] = null;
// Pointer to the right child node
}
}
// Performs a Depth-First Search (DFS) in Preorder traversal
// Preorder: Visit Root -> Traverse Left -> Traverse Right
function preorderTraversal(node) {
if (node === null) {
return;
// Base case: if node is null, stop recursion
}
// 1. Visit the current node (Root)
[Link]([Link]);
// 2. Traverse the left subtree
preorderTraversal([Link]);
// 3. Traverse the right subtree
preorderTraversal([Link]);
}
// Example Tree Structure:
/* 10
Laurence Svekis Learn More [Link]
/ \
5 15
/ \ \
2 7 20 */
const root = new TreeNode(10);
[Link] = new TreeNode(5);
[Link] = new TreeNode(15);
[Link] = new TreeNode(2);
[Link] = new TreeNode(7);
[Link] = new TreeNode(20);
[Link]("Preorder Traversal (Root -> Left -> Right):");
preorderTraversal(root); // Expected: 10, 5, 2, 7, 15, 20
// Another example tree
/* A
/ \
B C
/
D */
const root2 = new TreeNode('A');
[Link] = new TreeNode('B');
[Link] = new TreeNode('C');
[Link] = new TreeNode('D');
[Link]("\nPreorder Traversal for another tree:");
preorderTraversal(root2);
// Expected: A, B, D, C
Exercise 90: Tree Traversal (Breadth-First Search -
Level Order)
// Exercise 90: Tree Traversal (Breadth-First Search - Level Order)
// Reusing TreeNode class from Exercise 89
class TreeNode {
constructor(value) {
[Link] = value;
[Link] = null;
[Link] = null;
}
}
Laurence Svekis Learn More [Link]
// Performs a Breadth-First Search (BFS) / Level-Order Traversal
function levelOrderTraversal(root) {
if (root === null) {
return;
// Base case: empty tree
}
// Use a queue to keep track of nodes to visit
// (A simple array can act as a queue using push/shift)
const queue = [];
[Link](root);
[Link]("Level Order Traversal (BFS):");
while ([Link] > 0) {
const currentNode = [Link]();
// Dequeue the first node (FIFO)
[Link]([Link]);
// Visit the current node
// Enqueue its left child if it exists
if ([Link] !== null) {
[Link]([Link]);
}
// Enqueue its right child if it exists
if ([Link] !== null) {
[Link]([Link]);
}
}
}
// Example Tree Structure (same as Ex 89):
/* 10
/ \
5 15
/ \ \
2 7 20 */
const root = new TreeNode(10);
[Link] = new TreeNode(5);
[Link] = new TreeNode(15);
[Link] = new TreeNode(2);
[Link] = new TreeNode(7);
[Link] = new TreeNode(20);
levelOrderTraversal(root); // Expected: 10, 5, 15, 2, 7, 20
Laurence Svekis Learn More [Link]
// Another example tree
/* A
/ \
B C
/
D */
const root2 = new TreeNode('A');
[Link] = new TreeNode('B');
[Link] = new TreeNode('C');
[Link] = new TreeNode('D');
[Link]("\nLevel Order Traversal for another tree:");
levelOrderTraversal(root2);
// Expected: A, B, C, D
Exercise 91: Currying a Function
// Exercise 91: Currying a Function
// The original function we want to curry
function sum(a, b, c) {
return a + b + c;
}
// The curry function
function curry(func) {
// Returns a new function that handles the currying logic
return function curried(...args) {
// If the number of arguments received is enough for the original function,
// execute the original function with these arguments.
if ([Link] >= [Link]) { // [Link] gives the number of expected
arguments
return [Link](this, args);
} else {
// If not enough arguments, return another function that expects more arguments.
// This new function will concatenate the previously received arguments with the
new ones.
return function(...nextArgs) {
return [Link](this, [Link](nextArgs));
};
}
Laurence Svekis Learn More [Link]
};
}
// Demonstrate currying
const curriedSum = curry(sum);
[Link]("Curried Sum (one by one):", curriedSum(1)(2)(3));
// Expected: 6
[Link]("Curried Sum (two then one):", curriedSum(1, 2)(3));
// Expected: 6
[Link]("Curried Sum (all at once):", curriedSum(1, 2, 3));
// Expected: 6
// Example with another function
function multiply(a, b, c, d) {
return a * b * c * d;
}
const curriedMultiply = curry(multiply);
[Link]("Curried Multiply:", curriedMultiply(2)(3)(4)(5)); // Expected: 120
[Link]("Curried Multiply:", curriedMultiply(2, 3)(4, 5));
// Expected: 120
Exercise 92: Partial Application
// Exercise 92: Partial Application
function greet(greeting, name, punctuation) {
[Link](`${greeting}, ${name}${punctuation}`);
}
// --- Method 1: Using .bind() for partial application ---
// .bind(thisArg, arg1, arg2, ...)
// - The first argument is the 'this' context (null or undefined here for global functions)
// - Subsequent arguments are prepended to the arguments of the original function
const sayHelloWithBind = [Link](null, "Hello", "!");
// Pre-fills greeting and punctuation
[Link]("--- Using .bind() ---");
sayHelloWithBind("Alice"); // Expected: Hello, Alice!
sayHelloWithBind("Bob"); // Expected: Hello, Bob!
// --- Method 2: Manual Partial Application using a Closure ---
// Create a higher-order function that returns a new function
// The inner function closes over the pre-filled arguments
function createGreeting(greeting, punctuation) {
Laurence Svekis Learn More [Link]
return function(name) { // This is the partially applied function
greet(greeting, name, punctuation);
};
}
const sayHiExclamatory = createGreeting("Hi", "!");
const sayGoodMorningPeriod = createGreeting("Good morning", ".");
[Link]("\n--- Using Closure ---");
sayHiExclamatory("Charlie");
// Expected: Hi, Charlie!
sayGoodMorningPeriod("Diana"); // Expected: Good morning, Diana.
// Another example of partial application with bind
function calculateDiscount(price, discountPercentage) {
return price * (1 - discountPercentage);
}
const applyTenPercentDiscount = [Link](null, 0.10); // Pre-fills
discountPercentage
[Link]("\nPrice after 10% discount on 100:", applyTenPercentDiscount(100));
// Expected: 90
[Link]("Price after 10% discount on 250:", applyTenPercentDiscount(250));
// Expected: 225
Exercise 93: Function Composition
// Exercise 93: Function Composition
// Simple functions to compose
const add2 = num => num + 2;
const multiply3 = num => num * 3;
const square = num => num * num;
const negate = num => -num;
// The compose function (applies functions from right to left)
function compose(...funcs) {
// Returns a new function that takes an initial argument
return function(initialArg) {
// Use reduceRight to apply functions from right to left
// The accumulator (acc) starts with initialArg
// For each function (fn), it's called with the current accumulator's value
return [Link]((acc, fn) => fn(acc), initialArg);
};
Laurence Svekis Learn More [Link]
}
// The pipe function (alternative, applies functions from left to right)
function pipe(...funcs) {
return function(initialArg) {
return [Link]((acc, fn) => fn(acc), initialArg);
};
}
// Demonstrate composition
const composedFunc = compose(square, multiply3, add2);
// (5 + 2) => 7
// (7 * 3) => 21
// (21 * 21) => 441
[Link]("compose(square, multiply3, add2)(5):", composedFunc(5));
// Expected: 441
const composedAndNegated = compose(negate, square, add2); // (3 + 2) => 5
// (5 * 5) => 25
// (-25) => -25
[Link]("compose(negate, square, add2)(3):", composedAndNegated(3));
// Expected: -25
// Demonstrate pipe
const pipedFunc = pipe(add2, multiply3, square);
// (5 + 2) => 7
// (7 * 3) => 21
// (21 * 21) => 441
[Link]("pipe(add2, multiply3, square)(5):", pipedFunc(5));
// Expected: 441 (same result as compose in this specific case, but order differs)
Exercise 94: Singleton Pattern
// Exercise 94: Singleton Pattern
class Logger {
// Private static field to hold the single instance
static #instance = null;
// Private constructor to prevent direct instantiation
constructor() {
if (Logger.#instance) {
// If an instance already exists, throw an error to prevent direct calls
throw new Error("Logger instance already exists. Use [Link]()
Laurence Svekis Learn More [Link]
instead.");
}
[Link] = []; // To store log messages
[Link]("Logger: Initializing new instance...");
}
// Static method to get the single instance of the Logger
static getInstance() {
if (!Logger.#instance) {
// If no instance exists, create one
Logger.#instance = new Logger();
}
return Logger.#instance; // Return the existing instance
}
// Method to log a message
log(message) {
const timestamp = new Date().toISOString();
const logEntry = `${timestamp} - ${message}`;
[Link](logEntry);
[Link](`LOG: ${logEntry}`);
}
// Method to get all logs
getLogs() {
return [Link];
}
}
// Demonstrate the Singleton pattern
[Link]("Attempting to get Logger instances...");
const logger1 = [Link]();
const logger2 = [Link]();
// This should return the same instance as logger1
[Link]("\nAre logger1 and logger2 the same instance?", logger1 === logger2);
// Expected: true
[Link]("Application started.");
[Link]("User logged in.");
[Link]("\nAll logs from logger1:", [Link]());
[Link]("All logs from logger2:", [Link]());
// Should be the same logs as logger1
// Try to create a new instance directly (should throw an error)
try {
Laurence Svekis Learn More [Link]
const logger3 = new Logger();
} catch (e) {
[Link]("\nCaught an error when trying to instantiate Logger directly:",
[Link]);
}
Exercise 95: Factory Pattern (Simple)
// Exercise 95: Factory Pattern (Simple)
// 1. Define product classes (or constructor functions)
class Car {
constructor(options) {
[Link] = [Link] ||
"Generic Car";
[Link] = [Link] || "Model X";
[Link] = [Link] || 4;
}
drive() {
[Link](`Driving the ${[Link]} ${[Link]} (Car).`);
}
}
class Motorcycle {
constructor(options) {
[Link] = [Link] || "Generic Moto";
[Link] = [Link] || "Model Y";
[Link] = [Link] || 250;
}
ride() {
[Link](`Riding the ${[Link]} ${[Link]} (Motorcycle).`);
}
}
class Bicycle {
constructor(options) {
[Link] = [Link] ||
"Generic Bike";
[Link] = [Link] || "Model Z";
[Link] = [Link] || 1;
}
Laurence Svekis Learn More [Link]
pedal() {
[Link](`Pedaling the ${[Link]} ${[Link]} (Bicycle).`);
}
}
// 2. Implement the Factory class
class VehicleFactory {
createVehicle(type, options) {
switch ([Link]()) {
case 'car':
return new Car(options);
case 'motorcycle':
return new Motorcycle(options);
case 'bicycle':
return new Bicycle(options);
default:
throw new Error(`Unknown vehicle type: ${type}`);
}
}
}
// Demonstrate the Factory usage
const factory = new VehicleFactory();
const myCar = [Link]('car', { brand: 'Toyota', model: 'Camry', doors: 4 });
const myMotorcycle = [Link]('motorcycle', { brand: 'Honda', model:
'CBR500R', engineCC: 500 });
const myBicycle = [Link]('bicycle', { brand: 'Schwinn', model: 'Cruiser',
gears: 7 });
[Link]("Created Vehicles:");
[Link](myCar);
[Link]();
[Link](myMotorcycle);
[Link]();
[Link](myBicycle);
[Link]();
try {
const unknownVehicle = [Link]('boat', { brand: 'SeaRay' });
} catch (e) {
[Link]("\nCaught error for unknown vehicle type:", [Link]);
}
Laurence Svekis Learn More [Link]
Exercise 96: Observer Pattern (Using Custom Event
Emitter)
// Exercise 96: Observer Pattern (Using Custom Event Emitter)
// Reusing the EventEmitter class from Exercise 67
class EventEmitter {
constructor() {
[Link] = new Map();
}
on(eventName, listener) {
if () {
[Link](eventName, []);
}
[Link](eventName).push(listener);
// [Link](`[EventEmitter] Registered listener for '${eventName}'.`);
}
emit(eventName, ...args) {
const eventListeners = [Link](eventName);
if (eventListeners) {
// [Link](`[EventEmitter] Emitting event '${eventName}' with args:
${[Link](args)}`);
[Link](listener => {
try {
listener(...args);
} catch (e) {
[Link](`[EventEmitter] Error in listener for '${eventName}':`, e);
}
});
} else {
// [Link](`[EventEmitter] No listeners registered for '${eventName}'.`);
}
}
off(eventName, listenerToRemove) {
const eventListeners = [Link](eventName);
if (eventListeners) {
const index = [Link](listenerToRemove);
if (index > -1) {
[Link](index, 1);
Laurence Svekis Learn More [Link]
// [Link](`[EventEmitter] Unregistered listener for '${eventName}'.`);
} else {
// [Link](`[EventEmitter] Listener not found for '${eventName}'.`);
}
} else {
// [Link](`[EventEmitter] No listeners registered for '${eventName}'.`);
}
}
}
// The Subject (Publisher) that holds state and notifies observers
class Subject {
constructor(initialState) {
[Link] = new EventEmitter();
[Link] = initialState;
[Link](`Subject initialized with state: ${[Link]}`);
}
// Method for observers to subscribe
subscribe(listener) {
[Link]('stateChange', listener);
[Link]("Observer subscribed to 'stateChange' event.");
}
// Method for observers to unsubscribe
unsubscribe(listener) {
[Link]('stateChange', listener);
[Link]("Observer unsubscribed from 'stateChange' event.");
}
// Method to change the subject's state and notify observers
changeState(newState) {
if ([Link] !== newState) {
[Link] = newState;
[Link](`\nSubject state changed to: ${[Link]}`);
[Link]('stateChange', [Link]); // Emit the event with the new state
} else {
[Link](`\nState is already '${[Link]}', no change.`);
}
}
getCurrentState() {
return [Link];
}
Laurence Svekis Learn More [Link]
}
// Observer functions (can be part of classes/objects too)
const displayLogger = (newState) => [Link](`Logger: State updated to ->
${newState}`);
const alertUser = (newState) => {
if (newState === 'error') {
[Link](`ALERT: An error state was detected! Current state: ${newState}`);
}
};
const simpleReporter = (newState) => [Link](`Reporter: New state is
${newState}.`);
// Demonstrate the Observer pattern
const dataSubject = new Subject("initial_status");
// Observers subscribe to the subject
[Link](displayLogger);
[Link](alertUser);
[Link](simpleReporter);
// Change the subject's state, which will notify all subscribed observers
[Link]("loading");
[Link]("data_fetched");
[Link]("error");
// This will trigger the alertUser observer
[Link]("error"); // No change, no notification
// Unsubscribe an observer
[Link](displayLogger);
[Link]("resolved");
// displayLogger will no longer be notified
Exercise 97: Mixin Pattern
// Exercise 97: Mixin Pattern
// 1. Define the Mixin (a simple object containing methods to be mixed in)
const LoggerMixin = {
// The 'this' context within this method will refer to the object
// (or class instance) that the mixin is applied to.
log(message) {
// Use [Link] to identify the class instance
[Link](`[${[Link]} LOG]: ${message}`);
Laurence Svekis Learn More [Link]
},
// You can add more methods or properties here
logError(errorMsg) {
[Link](`[${[Link]} ERROR]: ${errorMsg}`);
}
};
// 2. Define classes that will consume the mixin
class User {
constructor(name) {
[Link] = name;
}
greet() {
[Link](`Hello, I am ${[Link]}.`);
// Uses the mixed-in log method
}
}
class Product {
constructor(name, price) {
[Link] = name;
[Link] = price;
}
displayPrice() {
[Link](`The price of ${[Link]} is $${[Link]}.`);
// Uses the mixed-in log method
}
}
// 3. Apply the Mixin to the prototypes of the classes
// [Link] copies properties from source objects to a target object.
// By assigning to the .prototype, all instances of User and Product will inherit these
methods.
[Link]([Link], LoggerMixin);
[Link]([Link], LoggerMixin);
// Demonstrate usage
const user = new User("Alice");
[Link](); // Expected: [User LOG]: Hello, I am Alice.
[Link]("User specific activity.");
// Directly calling the mixed-in method
[Link]("Failed to fetch user data.");
// Using another mixed-in method
Laurence Svekis Learn More [Link]
const product = new Product("Laptop", 1200);
[Link]();
// Expected: [Product LOG]: The price of Laptop is $1200.
[Link]("Product added to cart.");
// Directly calling the mixed-in method
Exercise 98: Module Pattern (Revealing Module
Pattern)
// Exercise 98: Module Pattern (Revealing Module Pattern)
const ShoppingCart = (function() { // Immediately Invoked Function Expression (IIFE)
// Private variables (not accessible from outside the IIFE)
let items = [];
let nextItemId = 1;
// Private helper function
function _findItemIndex(itemName) {
return [Link](item => [Link] === itemName);
}
// Public methods that are exposed
function addItem(name, price, quantity = 1) {
const existingIndex = _findItemIndex(name);
if (existingIndex > -1) {
items[existingIndex].quantity += quantity;
[Link](`Updated quantity for "${name}".`);
} else {
[Link]({ id: nextItemId++, name, price, quantity });
[Link](`Added "${name}" to cart.`);
}
}
function removeItem(name) {
const index = _findItemIndex(name);
if (index > -1) {
[Link](index, 1);
[Link](`Removed "${name}" from cart.`);
} else {
Laurence Svekis Learn More [Link]
[Link](`"${name}" not found in cart.`);
}
}
function getTotal() {
return [Link]((total, item) => total + ([Link] * [Link]), 0);
}
function getCartItems() {
// Return a copy to prevent external modification of the private 'items' array
return [...items];
}
function _clearCart() { // This could be a private helper not exposed
items = [];
nextItemId = 1;
[Link]("Cart cleared (private method).");
}
// The "revealing" part: expose public methods
return {
addItem: addItem,
removeItem: removeItem,
getTotal: getTotal,
getItems: getCartItems, // Renaming for public interface
// clear: _clearCart // Uncomment to expose a 'clear' method
};
})(); // The IIFE is immediately executed, and its return value is assigned to
ShoppingCart
// Demonstrate using the ShoppingCart module
[Link]("--- Shopping Cart Actions ---");
[Link]("Laptop", 1200);
[Link]("Mouse", 25, 2);
[Link]("Keyboard", 75);
[Link]("Laptop", 1200); // Add laptop again to update quantity
[Link]("Current cart items:", [Link]());
[Link]("Cart total:", [Link]()); // Expected: 1200*2 + 25*2 + 75 =
2400 + 50 + 75 = 2525
Laurence Svekis Learn More [Link]
[Link]("Mouse");
[Link]("Cart total after removing Mouse:", [Link]()); // Expected:
2400 + 75 = 2475
[Link]("Current cart items:", [Link]());
// Trying to access private variables/methods directly (will fail)
// [Link]([Link]); // Undefined
// ShoppingCart._findItemIndex("Laptop");
// TypeError
Exercise 99: Higher-Order Components (Conceptual)
// Exercise 99: Higher-Order Components (Conceptual)
// 1. Definition of a "Component" (as a simple function for this conceptual example)
// In React, this would be a React component (functional or class-based).
const UserProfileComponent = (props) => {
[Link](`Rendering UserProfile for: ${[Link]}, Status:
${[Link]}`);
return `<div><h1>User Profile for ${[Link]}</h1><p>Status:
${[Link]}</p></div>`;
};
// 2. The Higher-Order Component (HOC)
// A HOC is a function that takes a component (WrappedComponent)
// and returns a new component with enhanced functionality.
function withLoading(WrappedComponent) {
// The HOC returns a new functional component
return function EnhancedComponent(props) {
if ([Link]) {
[Link]("Displaying loading state...");
return "<div>Loading...</div>"; // Render loading UI
} else if ([Link]) {
[Link]("Displaying error state...");
return `<div>Error: ${[Link] || 'Something went wrong.'}</div>`; //
Render error UI
} else {
// If not loading and no error, render the original component with its props
[Link]("Rendering wrapped component.");
// In a real React app, you'd use <WrappedComponent {...props} />
Laurence Svekis Learn More [Link]
// Here, we just call the function as a stand-in.
return WrappedComponent(props);
}
};
}
// 3. Applying the HOC
// Create an enhanced version of UserProfileComponent
const EnhancedUserProfile = withLoading(UserProfileComponent);
// Demonstrate usage of the Enhanced Component
[Link]("--- First Render (Loading) ---");
[Link](EnhancedUserProfile({ isLoading: true }));
// Expected: <div>Loading...</div>
[Link]("\n--- Second Render (Data Loaded) ---");
[Link](EnhancedUserProfile({ isLoading: false, userName: "Alice", status: "Active"
}));
// Expected: <div><h1>User Profile for Alice</h1><p>Status: Active</p></div>
[Link]("\n--- Third Render (Error) ---");
[Link](EnhancedUserProfile({ isLoading: false, error: new Error("Network failed")
}));
// Expected: <div>Error: Network failed</div>
[Link]("\n--- Fourth Render (No Data, No Error) ---");
[Link](EnhancedUserProfile({ isLoading: false, userName: "Bob", status:
"Inactive" }));
Exercise 100: Web Workers (Conceptual)
// Exercise 100: Web Workers (Conceptual)
[Link]("--- Web Workers Conceptual Example ---");
[Link]("Web Workers allow JavaScript code to run in a background thread,
separate from the main execution thread.");
[Link]("This prevents heavy computations from blocking the UI (main thread),
keeping the page responsive.");
[Link]("They do NOT have direct access to the DOM or window object.");
[Link]("Communication between the main thread and a worker happens via
messages.");
// --- Conceptual [Link] code ---
[Link]("\n--- Main Thread (simulated) ---");
[Link]("Main thread: Starting a heavy calculation in a Web Worker...");
Laurence Svekis Learn More [Link]
// Imagine [Link] contains the heavy computation logic
// const myWorker = new Worker('[Link]');
// In a real browser, this would create the worker
// Simulate worker communication (since we can't spawn actual workers here)
function simulateWorkerCommunication(workerFile, dataToPost) {
[Link]("Main thread: Sending data to simulated worker:", dataToPost);
// Simulate the worker's onmessage
setTimeout(() => {
[Link]("Simulated Worker: Received message from main thread.");
// Simulate the heavy calculation
const result = performHeavyCalculation([Link]); // Calls the heavy
function defined below
[Link]("Simulated Worker: Sending result back to main thread.");
// Simulate the worker's postMessage
setTimeout(() => {
[Link]("Main thread: Received result from simulated worker:", result);
[Link]("Main thread: UI remains responsive during heavy calculation.");
}, 50); // Small delay to simulate message passing overhead
}, 100);
}
// --- Heavy Calculation (would typically be in [Link]) ---
function performHeavyCalculation(num) {
[Link]("Worker: Performing heavy calculation...");
let sum = 0;
// This loop will block the worker thread, but not the main browser UI thread
for (let i = 0; i < num; i++) {
sum += [Link](i) * [Link](i + 1);
// A somewhat CPU-intensive calculation
}
return `Calculated sum of ${[Link](2)} for ${num} iterations.`;
}
// Start the simulated heavy computation
simulateWorkerCommunication("[Link]", { type: 'startCalculation', data: 10000000
});
// A large number for computation
[Link]("Main thread: This message appears immediately, demonstrating
non-blocking behavior.");
[Link]("Main thread: User can interact with the page while calculation is in
progress.");
Laurence Svekis Learn More [Link]
// Benefits of Web Workers:
[Link]("\nBenefits of Web Workers:");
[Link]("- **Improved UI Responsiveness:** Prevents the main thread from
freezing during long-running tasks.");
[Link]("- **Parallel Execution:** Achieves a form of multi-threading in the
browser.");
[Link]("- **Better Performance:** Distributes workload across threads.");
Laurence Svekis Learn More [Link]