javascript
exercises
exercises.js⚡javascript
/**
* 21.5 Capstone Projects - Exercises
*
* Final project exercises combining all learned concepts
*/
/**
* Final Project: Build Your Own Application
*
* Choose ONE of the following projects to implement.
* Each project should demonstrate:
* - Clean code architecture
* - Security best practices
* - Performance optimizations
* - Appropriate design patterns
* - Error handling
* - Testing
*/
// ============================================================
// PROJECT OPTION 1: Note-Taking App with Sync
// ============================================================
/**
* Requirements:
*
* 1. Core Features:
* - Create, edit, delete notes
* - Rich text formatting
* - Tags and categories
* - Search functionality
*
* 2. Data Management:
* - Local storage with IndexedDB
* - Sync with mock API
* - Conflict resolution
* - Offline support
*
* 3. Security:
* - Input sanitization
* - XSS prevention
* - Secure storage
* - Content validation
*
* 4. Performance:
* - Debounced auto-save
* - Lazy loading
* - Virtual scrolling for note list
* - Memoized search results
*/
class NoteApp {
constructor() {
// TODO: Initialize the note-taking application
// - Set up storage
// - Initialize event system
// - Load existing notes
}
// Note CRUD operations
async createNote(data) {
// TODO: Create a new note with validation
}
async updateNote(id, data) {
// TODO: Update note with conflict detection
}
async deleteNote(id) {
// TODO: Soft delete with recovery option
}
// Search and filtering
searchNotes(query) {
// TODO: Implement fuzzy search with memoization
}
filterByTag(tag) {
// TODO: Filter notes by tag
}
// Sync management
async syncWithServer() {
// TODO: Implement sync with conflict resolution
}
// Export functionality
exportNotes(format) {
// TODO: Export notes as JSON, Markdown, or HTML
}
}
// ============================================================
// PROJECT OPTION 2: Budget Tracker
// ============================================================
/**
* Requirements:
*
* 1. Core Features:
* - Track income and expenses
* - Categories and budgets
* - Recurring transactions
* - Reports and charts
*
* 2. Data Management:
* - Transaction history
* - Monthly summaries
* - Budget tracking
* - Data export/import
*
* 3. Security:
* - Sensitive data encryption
* - Input validation
* - Secure calculations
* - Data integrity checks
*
* 4. Performance:
* - Efficient aggregations
* - Cached reports
* - Virtualized transaction list
* - Optimized chart rendering
*/
class BudgetTracker {
constructor() {
// TODO: Initialize the budget tracker
// - Set up categories
// - Load transaction history
// - Calculate running balances
}
// Transaction management
addTransaction(data) {
// TODO: Add income or expense with validation
}
editTransaction(id, data) {
// TODO: Edit transaction and recalculate
}
deleteTransaction(id) {
// TODO: Delete and update balances
}
// Budget management
setBudget(category, amount, period) {
// TODO: Set budget for category
}
getBudgetStatus() {
// TODO: Get current budget vs spending
}
// Reports
getMonthlyReport(month, year) {
// TODO: Generate monthly summary
}
getCategoryBreakdown(startDate, endDate) {
// TODO: Get spending by category
}
// Data export
exportToCSV() {
// TODO: Export transactions to CSV
}
}
// ============================================================
// PROJECT OPTION 3: Quiz/Flashcard App
// ============================================================
/**
* Requirements:
*
* 1. Core Features:
* - Create flashcard decks
* - Multiple question types
* - Spaced repetition
* - Progress tracking
*
* 2. Data Management:
* - Deck organization
* - Learning statistics
* - Progress persistence
* - Import/export decks
*
* 3. Security:
* - Content sanitization
* - Safe rendering
* - Score validation
* - Cheat prevention
*
* 4. Performance:
* - Efficient card selection
* - Cached deck data
* - Smooth animations
* - Optimized statistics
*/
class FlashcardApp {
constructor() {
// TODO: Initialize flashcard application
// - Load decks
// - Initialize spaced repetition algorithm
// - Set up statistics tracking
}
// Deck management
createDeck(name, description) {
// TODO: Create new deck
}
addCard(deckId, front, back, hints) {
// TODO: Add card to deck
}
editCard(cardId, data) {
// TODO: Edit existing card
}
// Study session
startSession(deckId, options) {
// TODO: Start study session
// Use spaced repetition to select cards
}
recordAnswer(cardId, correct, timeSpent) {
// TODO: Record answer and update intervals
}
// Progress tracking
getDeckProgress(deckId) {
// TODO: Get mastery progress for deck
}
getStudyStreak() {
// TODO: Calculate study streak
}
// Import/Export
exportDeck(deckId, format) {
// TODO: Export deck as JSON or Anki format
}
importDeck(data) {
// TODO: Import deck from file
}
}
// ============================================================
// PROJECT OPTION 4: Kanban Board
// ============================================================
/**
* Requirements:
*
* 1. Core Features:
* - Customizable columns
* - Drag and drop cards
* - Card details and comments
* - Labels and priorities
*
* 2. Data Management:
* - Board state persistence
* - Card ordering
* - Activity history
* - Multiple boards
*
* 3. Security:
* - Content validation
* - Safe drag-drop
* - XSS prevention
* - Data sanitization
*
* 4. Performance:
* - Efficient DOM updates
* - Throttled drag events
* - Optimistic updates
* - Memoized renders
*/
class KanbanBoard {
constructor(boardId) {
// TODO: Initialize kanban board
// - Load board data
// - Set up drag-drop handlers
// - Initialize column management
}
// Column management
addColumn(name, position) {
// TODO: Add new column
}
moveColumn(columnId, newPosition) {
// TODO: Reorder column
}
deleteColumn(columnId) {
// TODO: Delete column (with cards)
}
// Card management
addCard(columnId, data) {
// TODO: Add card to column
}
moveCard(cardId, targetColumnId, position) {
// TODO: Move card between columns
}
updateCard(cardId, data) {
// TODO: Update card details
}
// Filtering and search
filterCards(criteria) {
// TODO: Filter visible cards
}
searchCards(query) {
// TODO: Search cards
}
// Activity tracking
getCardActivity(cardId) {
// TODO: Get activity history
}
}
// ============================================================
// EVALUATION RUBRIC
// ============================================================
/**
* Your project will be evaluated on:
*
* 1. ARCHITECTURE (25 points)
* - Clean separation of concerns
* - Appropriate use of patterns
* - Modular, reusable code
* - Clear file organization
*
* 2. SECURITY (25 points)
* - Input validation everywhere
* - Output encoding
* - Secure data handling
* - Error message safety
*
* 3. PERFORMANCE (20 points)
* - Efficient algorithms
* - Proper caching
* - Lazy loading where appropriate
* - Memory management
*
* 4. CODE QUALITY (15 points)
* - Readable, self-documenting code
* - Consistent style
* - Meaningful names
* - Appropriate comments
*
* 5. ERROR HANDLING (15 points)
* - Graceful degradation
* - User-friendly messages
* - Recovery mechanisms
* - Logging
*/
// ============================================================
// STARTER TEMPLATE
// ============================================================
/**
* Use this template as a starting point for your project
*/
class ApplicationCore {
constructor(config = {}) {
this.config = config;
this.eventBus = new EventBusFinal();
this.store = new StoreFinal(config.storeName || 'app');
this.initialized = false;
}
async init() {
if (this.initialized) return;
try {
await this.store.init();
await this.loadInitialData();
this.setupEventHandlers();
this.initialized = true;
this.eventBus.emit('app:initialized');
} catch (error) {
console.error('Failed to initialize app:', error);
throw error;
}
}
async loadInitialData() {
// Override in subclass
}
setupEventHandlers() {
// Override in subclass
}
destroy() {
this.eventBus.clear();
this.initialized = false;
}
}
class EventBusFinal {
constructor() {
this.events = new Map();
}
on(event, handler) {
if (!this.events.has(event)) {
this.events.set(event, new Set());
}
this.events.get(event).add(handler);
return () => this.off(event, handler);
}
off(event, handler) {
this.events.get(event)?.delete(handler);
}
emit(event, data) {
this.events.get(event)?.forEach((handler) => {
try {
handler(data);
} catch (error) {
console.error(`Event handler error for ${event}:`, error);
}
});
}
clear() {
this.events.clear();
}
}
class StoreFinal {
constructor(name) {
this.name = name;
this.data = {};
}
async init() {
const saved = localStorage.getItem(this.name);
if (saved) {
try {
this.data = JSON.parse(saved);
} catch {
this.data = {};
}
}
}
get(key) {
return this.data[key];
}
set(key, value) {
this.data[key] = value;
this.persist();
}
delete(key) {
delete this.data[key];
this.persist();
}
persist() {
localStorage.setItem(this.name, JSON.stringify(this.data));
}
clear() {
this.data = {};
localStorage.removeItem(this.name);
}
}
// ============================================================
// UTILITY FUNCTIONS
// ============================================================
// Input sanitization
function sanitizeHTML(str) {
const temp = document.createElement('div');
temp.textContent = str;
return temp.innerHTML;
}
// Debounce
function debounce(fn, ms) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => fn.apply(this, args), ms);
};
}
// Throttle
function throttle(fn, ms) {
let lastCall = 0;
return function (...args) {
const now = Date.now();
if (now - lastCall >= ms) {
lastCall = now;
return fn.apply(this, args);
}
};
}
// Memoization
function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (!cache.has(key)) {
cache.set(key, fn.apply(this, args));
}
return cache.get(key);
};
}
// Generate unique ID
function generateId() {
return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// Deep clone
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (Array.isArray(obj)) return obj.map(deepClone);
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [key, deepClone(value)])
);
}
// ============================================================
// EXAMPLE SOLUTION: Minimal Note App
// ============================================================
/*
// SOLUTION: Note-Taking App Implementation
class NoteAppSolution extends ApplicationCore {
constructor() {
super({ storeName: 'notes-app' });
this.notes = [];
}
async loadInitialData() {
this.notes = this.store.get('notes') || [];
}
setupEventHandlers() {
this.eventBus.on('note:change', () => {
this.store.set('notes', this.notes);
});
}
createNote(data) {
const note = {
id: generateId(),
title: sanitizeHTML(data.title || 'Untitled'),
content: sanitizeHTML(data.content || ''),
tags: (data.tags || []).map(t => sanitizeHTML(t).slice(0, 50)),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deleted: false
};
this.notes.push(note);
this.eventBus.emit('note:change');
this.eventBus.emit('note:created', note);
return note;
}
updateNote(id, data) {
const note = this.notes.find(n => n.id === id);
if (!note || note.deleted) return null;
if (data.title !== undefined) note.title = sanitizeHTML(data.title);
if (data.content !== undefined) note.content = sanitizeHTML(data.content);
if (data.tags !== undefined) note.tags = data.tags.map(t => sanitizeHTML(t).slice(0, 50));
note.updatedAt = new Date().toISOString();
this.eventBus.emit('note:change');
this.eventBus.emit('note:updated', note);
return note;
}
deleteNote(id) {
const note = this.notes.find(n => n.id === id);
if (!note) return false;
note.deleted = true;
note.deletedAt = new Date().toISOString();
this.eventBus.emit('note:change');
this.eventBus.emit('note:deleted', note);
return true;
}
restoreNote(id) {
const note = this.notes.find(n => n.id === id);
if (!note || !note.deleted) return false;
note.deleted = false;
delete note.deletedAt;
this.eventBus.emit('note:change');
this.eventBus.emit('note:restored', note);
return true;
}
searchNotes = memoize((query) => {
const q = query.toLowerCase();
return this.notes.filter(n =>
!n.deleted && (
n.title.toLowerCase().includes(q) ||
n.content.toLowerCase().includes(q) ||
n.tags.some(t => t.toLowerCase().includes(q))
)
);
});
filterByTag(tag) {
return this.notes.filter(n => !n.deleted && n.tags.includes(tag));
}
getAllNotes() {
return this.notes.filter(n => !n.deleted);
}
getDeletedNotes() {
return this.notes.filter(n => n.deleted);
}
exportNotes(format = 'json') {
const notes = this.getAllNotes();
switch (format) {
case 'json':
return JSON.stringify(notes, null, 2);
case 'markdown':
return notes.map(n =>
`# ${n.title}\n\n${n.content}\n\nTags: ${n.tags.join(', ')}\n\n---\n`
).join('\n');
default:
throw new Error(`Unsupported format: ${format}`);
}
}
}
// Usage:
// const app = new NoteAppSolution();
// await app.init();
// app.createNote({ title: 'My First Note', content: 'Hello World!' });
// console.log(app.getAllNotes());
*/
console.log('=== Capstone Project Exercises ===');
console.log('Choose one project option and implement it fully.');
console.log('Use the starter template and utility functions provided.');
console.log('Refer to the evaluation rubric for grading criteria.');
// Export for use
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
NoteApp,
BudgetTracker,
FlashcardApp,
KanbanBoard,
ApplicationCore,
EventBusFinal,
StoreFinal,
sanitizeHTML,
debounce,
throttle,
memoize,
generateId,
deepClone,
};
}