Code

JavaScript Examples

Useful patterns and utilities I use regularly. Copy freely.

⏱️

Debounce Function

Limit how often a function fires — essential for search inputs and resize handlers.

debounce.js
function debounce(fn, delay = 300) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

// Usage
const search = debounce((query) => {
  console.log('Searching for:', query);
}, 500);

// Rapid calls only fire once after 500ms pause
search('h');
search('he');
search('hello'); // Only this one runs
📋

Deep Clone

Create a true deep copy of any object without shared references.

deep-clone.js
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  if (Array.isArray(obj)) return obj.map(deepClone);

  const cloned = {};
  for (const key of Object.keys(obj)) {
    cloned[key] = deepClone(obj[key]);
  }
  return cloned;
}

// Usage
const original = {
  name: 'Alice',
  scores: [95, 87, 92],
  meta: { joined: new Date() },
};

const copy = deepClone(original);
copy.scores.push(100);
console.log(original.scores); // [95, 87, 92] — unaffected!
📡

Event Emitter

A lightweight pub/sub system for decoupled communication between modules.

event-emitter.js
class EventEmitter {
  constructor() {
    this.events = {};
  }

  on(event, listener) {
    (this.events[event] ||= []).push(listener);
    return () => this.off(event, listener);
  }

  off(event, listener) {
    this.events[event] = this.events[event]
      ?.filter((fn) => fn !== listener);
  }

  emit(event, ...args) {
    this.events[event]?.forEach((fn) => fn(...args));
  }
}

// Usage
const bus = new EventEmitter();
const unsub = bus.on('message', (msg) => {
  console.log('Received:', msg);
});

bus.emit('message', 'Hello!');  // "Received: Hello!"
unsub();                         // Unsubscribe
bus.emit('message', 'Goodbye');  // Nothing happens
🚦

Throttle Function

Ensure a function runs at most once per interval — ideal for scroll and resize events.

throttle.js
function throttle(fn, interval = 300) {
  let lastTime = 0;
  let timer = null;

  return function (...args) {
    const now = Date.now();
    const remaining = interval - (now - lastTime);

    if (remaining <= 0) {
      clearTimeout(timer);
      lastTime = now;
      fn.apply(this, args);
    } else if (!timer) {
      timer = setTimeout(() => {
        lastTime = Date.now();
        timer = null;
        fn.apply(this, args);
      }, remaining);
    }
  };
}

// Usage — fires at most once per 200ms
window.addEventListener(
  'scroll',
  throttle(() => console.log('Scrolled!'), 200)
);
🏊

Promise Pool

Run async tasks with a concurrency limit to avoid overwhelming APIs.

promise-pool.js
async function promisePool(tasks, concurrency = 3) {
  const results = [];
  let index = 0;

  async function worker() {
    while (index < tasks.length) {
      const i = index++;
      results[i] = await tasks[i]();
    }
  }

  const workers = Array.from(
    { length: Math.min(concurrency, tasks.length) },
    () => worker()
  );

  await Promise.all(workers);
  return results;
}

// Usage — fetch 10 URLs, 3 at a time
const urls = Array.from({ length: 10 }, (_, i) =>
  () => fetch(`/api/item/${i}`).then((r) => r.json())
);

const results = await promisePool(urls, 3);

Reactive State

A minimal reactive state system using JavaScript Proxies.

reactive-state.js
function reactive(initial, onChange) {
  return new Proxy(initial, {
    set(target, key, value) {
      const old = target[key];
      target[key] = value;
      if (old !== value) {
        onChange(key, value, old);
      }
      return true;
    },
  });
}

// Usage
const state = reactive({ count: 0, name: 'World' }, (key, val, old) => {
  console.log(`${key} changed: ${old} → ${val}`);
});

state.count = 1;    // "count changed: 0 → 1"
state.name = 'JS';  // "name changed: World → JS"
state.count = 1;    // No log — value didn't change