JavaScript Debugging Cheat Sheet

Console Debugging

Basic Console Methods

  • Use console.log(), info(), warn(), and error() to track messages and warnings.
  • Organize logs with group() and time actions with time() and timeEnd().
  • Display data cleanly using console.table().
console.log('Debug message');
console.group('User Ops');
console.log('Creating...');
console.groupEnd();
console.table([{ name: 'John' }, { name: 'Jane' }]);
console.time('fetchData');
// async call...
console.timeEnd('fetchData');

Advanced Console Techniques

  • Trace execution with console.trace().
  • Add logic to logs or style them for emphasis.
  • Count actions with count() and reset them with countReset().
console.assert(user.age >= 18, 'User must be 18');
console.trace('Where is this called from?');
console.count('API call');

Debugging Objects and Arrays

  • Use console.dir() for deep object views.
  • Spread arrays for full content visibility.
  • Log object keys, values, and entries clearly.
console.dir(user, { depth: null });
console.log([...array]);
console.log(Object.entries(user));

Error Handling

Try-Catch Blocks

  • Catch errors and handle fallback logic.
  • Always log error.message and error.stack for context.
  • In async functions, use try/catch with await.
try {
  const result = risky();
} catch (error) {
  console.error(error.message);
}

Custom Error Classes

  • Create your own Error types like ValidationError or NetworkError.
  • Helps categorize and respond to different failure types.
class ValidationError extends Error {
  constructor(msg, field) {
    super(msg);
    this.field = field;
  }
}

Global Error Handling

  • Catch uncaught errors in the browser or Node.js globally.
  • Use window.addEventListener('error') and unhandledrejection.
window.addEventListener('error', event => {
  console.error('Global error:', event.message);
});

Debugging Tools

Source Maps

  • Enable source maps to trace back to original source files.
  • Use with Babel or Webpack for better error visibility in minified code.
// webpack.config.js
devtool: 'source-map'

Debugger Statement

  • Use debugger to pause code in DevTools when a condition is met.
  • Especially useful for inspecting variables at specific logic points.
if (user.age < 18) debugger;

Network Debugging

  • Wrap fetch and XHR to log requests and responses.
  • Monitor network resource loading with PerformanceObserver.
window.fetch = (...args) => {
  console.log('Fetch:', args);
  return originalFetch(...args);
};

Troubleshooting Common Issues

Undefined and Null Issues

  • Use optional chaining (?.) and nullish coalescing (??) to handle safely.
  • Log types and check for null/undefined clearly.
const age = user?.profile?.age ?? 0;
console.log(typeof value);

Async/Await Debugging

  • Use logs before/after each await to trace flow.
  • Wrap the whole sequence in try/catch to isolate failures.
try {
  const result = await step();
  console.log('Done:', result);
} catch (e) {
  console.error(e);
}

DOM Debugging

  • Check if DOM elements exist before interacting.
  • Use MutationObserver to track DOM changes.
  • Inspect event listeners with tools like getEventListeners().
const el = document.getElementById('myElement');
if (!el) console.error('Not found');

Memory Leak Detection

  • Use performance.memory to inspect memory usage (Chrome only).
  • Watch for event listeners that aren’t removed.
if ('memory' in performance) {
  console.log(performance.memory.usedJSHeapSize);
}

Debugging Utilities

Debug Helper Functions

  • Build centralized helpers for dev-only logging, timing, and error formatting.
const debug = {
  log: (label, data) => console.log(`${label}:`, data),
  error: (label, err) => console.error(`${label}:`, err),
};

Environment Detection

  • Add conditional logging based on NODE_ENV.
  • Avoid debug logs in production automatically.
const isDev = process.env.NODE_ENV === 'development';
if (isDev) console.log('Only in dev!');