← Back to Articles

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 → Stop

Testing 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, Mocha

Code 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.js

Performance 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: