Advanced JavaScript Exercises (Part 4)
Lesson Objective:
Continue reinforcing core JavaScript concepts by working with more advanced topics like recursion, regular expressions, event delegation, dynamic form creation, custom data structures, and DOM manipulation. Learners will gain deeper insights into how JavaScript works by creating custom solutions to real-world problems without relying on any external libraries or frameworks.
Learning Outcomes:
- Strengthen understanding of recursion and how to implement recursive solutions.
- Work with regular expressions for string manipulation and validation.
- Master advanced DOM manipulation techniques.
- Create and manipulate custom data structures using pure JavaScript.
- Understand event delegation and use it effectively for optimizing event handling.
Exercise 1: Recursive Fibonacci
Learning Objective:
Learn how to implement a recursive function to generate Fibonacci numbers.
function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n – 1) + fibonacci(n – 2);
}
console.log(fibonacci(5)); // Output: 5
console.log(fibonacci(10)); // Output: 55
Explanation:
- This recursive function calculates the nth Fibonacci number.
- The function calls itself for n – 1 and n – 2, adding the results to generate the Fibonacci sequence.
Exercise 2: Regular Expression Email Validation
Learning Objective:
Understand how to use regular expressions for validating email addresses.
function validateEmail(email) {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailPattern.test(email);
}
console.log(validateEmail(‘test@example.com’)); // true
console.log(validateEmail(‘invalid-email’)); // false
Explanation:
- This exercise demonstrates how to use a regular expression to validate the format of an email address.
- The pattern ensures that the email contains a valid structure (text followed by an “@” and a domain).
Exercise 3: Event Delegation
Learning Objective:
Learn how to implement event delegation to manage events more efficiently.
<ul id=”itemList”>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<script>
document.getElementById(‘itemList’).addEventListener(‘click’, (event) => {
if (event.target.tagName === ‘LI’) {
alert(`You clicked ${event.target.textContent}`);
}
});
</script>
Explanation:
- Event delegation is a technique where a single event listener is added to a parent element to manage events from its children.
- This is more efficient for handling dynamically added elements or large lists of elements, as it avoids adding multiple event listeners.
Exercise 4: Dynamic Form Creation
Learning Objective:
Learn how to dynamically create and manipulate forms using JavaScript.
<form id=”dynamicForm”></form>
<button id=”addFieldBtn”>Add Input Field</button>
<script>
const form = document.getElementById(‘dynamicForm’);
const addFieldBtn = document.getElementById(‘addFieldBtn’);
addFieldBtn.addEventListener(‘click’, () => {
const input = document.createElement(‘input’);
input.type = ‘text’;
input.name = `field${form.children.length + 1}`;
input.placeholder = `Field ${form.children.length + 1}`;
form.appendChild(input);
});
</script>
Explanation:
- This exercise demonstrates how to dynamically create new form fields using JavaScript.
- A new input field is added to the form each time the “Add Input Field” button is clicked.
Exercise 5: Binary Search
Learning Objective:
Implement the binary search algorithm to find elements in a sorted array efficiently.
function binarySearch(arr, target) {
let left = 0;
let right = arr.length – 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid – 1;
}
}
return -1;
}
const arr = [1, 3, 5, 7, 9, 11];
console.log(binarySearch(arr, 5)); // Output: 2
console.log(binarySearch(arr, 12)); // Output: -1
Explanation:
- Binary search is an efficient algorithm for finding an item in a sorted array by repeatedly dividing the search space in half.
- It returns the index of the target element or -1 if the element is not found.
Exercise 6: Custom Queue Implementation
Learning Objective:
Learn how to implement a custom queue data structure using JavaScript.
class Queue {
constructor() {
this.items = [];
}
enqueue(element) {
this.items.push(element);
}
dequeue() {
return this.items.shift();
}
peek() {
return this.items[0];
}
isEmpty() {
return this.items.length === 0;
}
}
const queue = new Queue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
console.log(queue.dequeue()); // Output: 1
console.log(queue.peek()); // Output: 2
Explanation:
- This custom queue data structure demonstrates how to implement a first-in, first-out (FIFO) system.
- The enqueue method adds an element to the end, and dequeue removes the element from the front.
Exercise 7: Debounce Input Event
Learning Objective:
Implement a debouncing mechanism for handling frequent user input events efficiently.
<input type=”text” id=”searchInput” placeholder=”Type to search…”>
<script>
function debounce(func, delay) {
let timeout;
return function(…args) {
clearTimeout(timeout);
timeout = setTimeout(() => func(…args), delay);
};
}
const handleInput = debounce(() => {
console.log(‘Search triggered’);
}, 500);
document.getElementById(‘searchInput’).addEventListener(‘input’, handleInput);
</script>
Explanation:
- Debouncing ensures that a function is called only after a certain delay following the last event, which is useful for performance optimization, especially when handling frequent events like typing in an input field.
Exercise 8: Merge Sort Algorithm
Learning Objective:
Understand how to implement the merge sort algorithm using JavaScript.
function mergeSort(arr) {
if (arr.length <= 1) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
return merge(left, right);
}
function merge(left, right) {
const result = [];
let leftIndex = 0;
let rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}
const unsortedArray = [38, 27, 43, 3, 9, 82, 10];
console.log(mergeSort(unsortedArray)); // Output: [3, 9, 10, 27, 38, 43, 82]
Explanation:
- Merge sort is a divide-and-conquer algorithm that recursively divides the array into halves, sorts each half, and then merges them back together.
- It provides an efficient solution to sorting problems with a time complexity of O(n log n).
Exercise 9: Array Chunking
Learning Objective:
Learn how to split an array into chunks of specified size.
function chunkArray(arr, size) {
const chunks = [];
for (let i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
}
const array = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(chunkArray(array, 3)); // Output: [[1, 2, 3], [4, 5, 6], [7, 8]]
Explanation:
- Array chunking divides an array into smaller arrays (chunks) of a specified size.
- This technique is useful for processing large data sets in manageable portions.
Exercise 10: String Palindrome Check
Learning Objective:
Learn how to check whether a string is a palindrome (reads the same backward and forward).
function isPalindrome(str) {
const cleanedStr = str.replace(/[^A-Za-z0-9]/g, ”).toLowerCase();
return cleanedStr === cleanedStr.split(”).reverse().join(”);
}
console.log(isPalindrome(‘A man, a plan, a canal, Panama’)); // true
console.log(isPalindrome(‘Hello’)); // false
Explanation:
- This function checks whether a given string is a palindrome, meaning it reads the same forward and backward.
- The input string is first cleaned to remove non-alphanumeric characters and then converted to lowercase.
- The string is reversed and compared to the original cleaned string to determine if it is a palindrome.
Recap of Key Concepts:
These exercises push learners to explore important aspects of JavaScript, including:
- Recursive Algorithms (Fibonacci, Merge Sort): Mastering recursion for solving complex problems.
- Regular Expressions (Email Validation): Understanding how to validate and manipulate strings using patterns.
- Event Delegation: Efficient event handling through delegation to improve performance in dynamic applications.
- Custom Data Structures (Queue, Binary Search): Implementing basic data structures and algorithms manually.
- DOM Manipulation: Dynamically adding form elements, handling input events with debouncing, and processing user input.
- Algorithm Implementation: Sorting algorithms, binary search, and array chunking for optimizing and structuring data processing.
- Palindrome Check: Building simple but practical string manipulations to handle real-world tasks.
By completing these exercises, learners will be equipped with an even stronger grasp of the core JavaScript concepts and how to implement them effectively without relying on any external libraries or frameworks.