JavaScript: Professional
Debugging
// Console methods
console.log('Info');
console.warn('Warning');
console.error('Error');
console.table([{ a: 1 }, { a: 2 }]);
console.time('timer');
console.timeEnd('timer');
console.trace('Stack trace');
// Debugger statement
function problematic() {
debugger; // Breaks here in DevTools
// ... code
}
// Try/catch for debugging
try {
riskyOperation();
} catch (e) {
console.error('Operation failed', {
message: e.message,
stack: e.stack,
name: e.name
});
}Debouncing
// Debounce: Execute after delay
function debounce(fn, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
// Usage: Search input
const searchInput = document.getElementById('search');
const handleSearch = debounce((e) => {
fetch(`/api/search?q=${e.target.value}`);
}, 300);
searchInput.addEventListener('input', handleSearch);Throttling
// Throttle: Execute at most once per interval
function throttle(fn, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// Usage: Scroll handler
const handleScroll = throttle(() => {
console.log('Scrolling...', window.scrollY);
}, 100);
window.addEventListener('scroll', handleScroll);Memory Management
// Memory leaks to avoid
// 1. Forgotten event listeners
element.addEventListener('click', handler);
// Fix: Remove when done
element.removeEventListener('click', handler);
// 2. Closures holding references
function setup() {
const largeData = new Array(1000000);
element.onclick = () => console.log('clicked');
// largeData is kept in memory
}
// 3. Detached DOM elements
const list = document.getElementById('list');
list.remove();
// If you still reference 'list', it won't be garbage collected
list = null;
// 4. Timers not cleared
const interval = setInterval(() => {}, 1000);
// Fix: clearInterval(interval);
// Check memory in DevTools
// Performance tab → Record → Perform actions → StopTesting Basics
// Simple test function
function test(name, fn) {
try {
fn();
console.log(`✓ ${name}`);
} catch (e) {
console.error(`✗ ${name}: ${e.message}`);
}
}
function assertEqual(actual, expected) {
if (actual !== expected) {
throw new Error(`Expected ${expected}, got ${actual}`);
}
}
// Example tests
test('adds numbers', () => {
assertEqual(add(2, 3), 5);
});
test('returns string', () => {
assertEqual(typeof greet('John'), 'string');
});
// Use testing frameworks: Jest, Vitest, MochaCode Organization
// Module pattern
const UserService = {
async getUser(id) { /* ... */ },
async createUser(data) { /* ... */ },
validateEmail(email) { /* ... */ }
};
// Class-based organization
class ApiService {
constructor(baseURL) {
this.baseURL = baseURL;
}
async get(endpoint) { /* ... */ }
async post(endpoint, data) { /* ... */ }
}
// File structure
// /src
// /services/
// api.js
// auth.js
// /utils/
// helpers.js
// validators.js
// /components/
// Button.js
// Modal.jsPerformance Tips
// 1. Use event delegation
// Bad: Add listener to each item
items.forEach(item => item.addEventListener('click', handler));
// Good: Single listener on parent
list.addEventListener('click', (e) => {
if (e.target.matches('.item')) handler(e);
});
// 2. Minimize DOM access
// Bad: Multiple reflows
for (let i = 0; i < 100; i++) {
element.style.width = i + 'px';
}
// Good: Batch changes
element.style.cssText = 'width: 100px; height: 50px;';
// 3. Use DocumentFragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
fragment.appendChild(createItem(i));
}
list.appendChild(fragment);
// 4. Lazy load images
const img = document.createElement('img');
img.loading = 'lazy';
img.src = 'image.jpg';Key Takeaways
- Use console methods for effective debugging
- Debounce user input, throttle scroll/resize
- Clean up event listeners and timers
- Write tests for critical functions
- Organize code into modules and services
Next Steps
Continue with CSS deep dives or move to professional skills: