Optional Deep Dive Material for Session 2 (Optional)
2025-10-11
Optional Advanced Material
This document contains advanced JavaScript concepts that were moved from the main Session 2 lecture to keep the core session focused and manageable.
Prerequisites: Complete Session 2 main content first.
When to read: When you’re comfortable with JavaScript basics and want to deepen your understanding before or after Session 3.
While Session 2 covers basic map()
and filter()
, here are additional powerful array methods:
// Calculate total price
const prices = [19.99, 29.99, 39.99];
const total = prices.reduce((sum, price) => sum + price, 0);
// Result: 89.97
// Group reviews by rating
const reviews = [
{ rating: 5, comment: "Great!" },
{ rating: 4, comment: "Good" },
{ rating: 5, comment: "Excellent!" }
];
const groupedByRating = reviews.reduce((groups, review) => {
const rating = review.rating;
if (!groups[rating]) groups[rating] = [];
groups[rating].push(review);
return groups;
}, {});
// Result: { 4: [...], 5: [...] }
// Basic pattern (covered in Session 2)
async function fetchReviews() {
try {
const response = await fetch('/api/reviews');
const data = await response.json();
return data;
} catch (error) {
console.error('Error:', error);
return [];
}
}
// Advanced pattern with specific error types
async function fetchReviewsAdvanced(productId) {
try {
const response = await fetch(`/api/products/${productId}/reviews`);
if (!response.ok) {
if (response.status === 404) {
throw new Error('Product not found');
} else if (response.status === 500) {
throw new Error('Server error - please try again later');
} else {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
}
const data = await response.json();
return data;
} catch (error) {
if (error instanceof TypeError) {
// Network error
throw new Error('Network error - check your connection');
}
throw error; // Re-throw other errors
}
}
// Global error handler
window.addEventListener('error', (event) => {
console.error('Global error:', event.error);
// Send to logging service
// Show user-friendly message
});
// Unhandled promise rejection handler
window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled promise rejection:', event.reason);
event.preventDefault(); // Prevent console error
});
class ShoppingCart {
constructor() {
this.items = this.loadFromStorage();
}
addItem(product) {
const existingItem = this.items.find(item => item.id === product.id);
if (existingItem) {
existingItem.quantity += 1;
} else {
this.items.push({ ...product, quantity: 1 });
}
this.saveToStorage();
this.updateUI();
}
removeItem(productId) {
this.items = this.items.filter(item => item.id !== productId);
this.saveToStorage();
this.updateUI();
}
loadFromStorage() {
try {
return JSON.parse(localStorage.getItem('cart') || '[]');
} catch (error) {
console.error('Error loading cart:', error);
return [];
}
}
saveToStorage() {
try {
localStorage.setItem('cart', JSON.stringify(this.items));
} catch (error) {
console.error('Error saving cart:', error);
}
}
updateUI() {
// Update cart display
const cartElement = document.querySelector('#cart-items');
if (cartElement) {
cartElement.innerHTML = this.items.map(item => `
<div class="cart-item">
<span>${item.name}</span>
<span>Qty: ${item.quantity}</span>
<span>$${(item.price * item.quantity).toFixed(2)}</span>
</div>
`).join('');
}
}
}
// Usage
const cart = new ShoppingCart();
Instead of adding event listeners to every button:
// ❌ Bad: Multiple event listeners
document.querySelectorAll('.review-like-btn').forEach(btn => {
btn.addEventListener('click', handleLike);
});
// ✅ Good: Single delegated event listener
document.addEventListener('click', (event) => {
if (event.target.matches('.review-like-btn')) {
handleLike(event);
}
});
function createReviewCard(review) {
const card = document.createElement('div');
card.className = 'review-card bg-white p-4 rounded-lg shadow';
// Create star rating
const stars = Array.from({ length: 5 }, (_, i) => {
const star = document.createElement('span');
star.className = i < review.rating ? 'star-filled' : 'star-empty';
star.textContent = '★';
return star;
});
const starsContainer = document.createElement('div');
starsContainer.className = 'flex gap-1';
starsContainer.append(...stars);
// Create content
const title = document.createElement('h3');
title.textContent = review.title;
title.className = 'font-bold text-lg';
const content = document.createElement('p');
content.textContent = review.content;
content.className = 'text-gray-700 mt-2';
const author = document.createElement('div');
author.textContent = `By ${review.author} on ${review.date}`;
author.className = 'text-sm text-gray-500 mt-2';
// Assemble card
card.append(starsContainer, title, content, author);
return card;
}
function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Usage for search
const searchInput = document.querySelector('#search');
const debouncedSearch = debounce(performSearch, 300);
searchInput.addEventListener('input', (event) => {
debouncedSearch(event.target.value);
});
function performSearch(query) {
console.log('Searching for:', query);
// Perform actual search
}
function throttle(func, delay) {
let timeoutId;
let lastExecTime = 0;
return function (...args) {
const currentTime = Date.now();
if (currentTime - lastExecTime > delay) {
func.apply(this, args);
lastExecTime = currentTime;
} else {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
lastExecTime = Date.now();
}, delay - (currentTime - lastExecTime));
}
};
}
// Usage for scroll events
const throttledScrollHandler = throttle(handleScroll, 100);
window.addEventListener('scroll', throttledScrollHandler);
// Array destructuring with rest
const [first, second, ...rest] = reviews;
// Object destructuring with renaming
const { title: reviewTitle, rating: stars } = review;
// Nested destructuring
const { user: { name, profile: { age } } } = reviewData;
// Function parameter destructuring
function displayReview({ title, rating, author = 'Anonymous' }) {
console.log(`${title} - ${rating} stars by ${author}`);
}
In React Development: - Array methods: Essential for rendering lists and data manipulation - Error handling: Critical for user experience - Storage APIs: Less needed (React has state management) - DOM manipulation: Rarely needed (React handles DOM) - Performance: React has built-in optimizations
Recommendation: Focus on array methods and error handling first. The other topics become more relevant in specialized scenarios or when working outside React.
E. Bruno - Advanced JavaScript Concepts