Solution

const debounce = (fn, ms) => {
  // timeoutID is used to store the ID of the setTimeout, allowing it to be cleared later.
  let timeoutID = null;
  // Returns a new function that has debouncing functionality.
  return (...args) => {
    // Clears the current timeout, if any, to reset the wait time for the function call.
    clearTimeout(timeoutID);
    // Sets a new timeout. The original function fn will be called after the specified ms delay.
    timeoutID = setTimeout(() => {
      fn.call(this, ...args);
    }, ms);
  };
};

// Usage
window.addEventListener(
  "resize",
  debounce(() => {
    // Will be printed once in a second
    console.log("Resizing...");
  }, 1000)
);