Launch your tech mastery with us—your coding journey starts now!

JavaScript Polyfills Cheat Sheet

A comprehensive JavaScript Polyfills cheat sheet diagram displayed on a workspace desk, detailing code implementations for Array.map, Array.filter, Function.bind, and Promises for legacy browser support and interview preparation.

A Polyfill is a piece of code (usually a function) used to provide modern functionality on older browsers that do not natively support it. In interviews, it proves you understand the internal logic of the language.

1. Array Polyfills (The Functional 5)

 These are usually attached to Array.prototype so all arrays can use them.

Array.map

Creates a new array by applying a function to every element.

				
					<!--JavaScript-->

Array.prototype.myMap = function(callback) {
  let temp = [];
  for (let i = 0; i < this.length; i++) {
    // callback(currentValue, index, array)
    temp.push(callback(this[i], i, this));
  }
  return temp;
};

				
			

Array.filter

Creates a new array with elements that pass the test.

				
					<!--JavaScript-->

Array.prototype.myFilter = function(callback) {
  let temp = [];
  for (let i = 0; i < this.length; i++) {
    if (callback(this[i], i, this)) {
      temp.push(this[i]);
    }
  }
  return temp;
};

				
			

Array.reduce

Reduces the array to a single value.

				
					<!--JavaScript-->

Array.prototype.myReduce = function(callback, initialValue) {
  let accumulator = initialValue;
  
  for (let i = 0; i < this.length; i++) {
    // If initialValue is undefined, take first element as accumulator
    if (accumulator === undefined) {
      accumulator = this[i];
    } else {
      accumulator = callback(accumulator, this[i], i, this);
    }
  }
  return accumulator;
};
				
			

Array.forEach

Executes a function for each array element (returns nothing).

				
					<!--JavaScript-->

Array.prototype.myForEach = function(callback) {
  for (let i = 0; i < this.length; i++) {
    callback(this[i], i, this);
  }
};

				
			

Array.find

Returns the first element that satisfies the condition.

				
					<!--JavaScript-->

Array.prototype.myFind = function(callback) {
  for (let i = 0; i < this.length; i++) {
    if (callback(this[i], i, this)) {
      return this[i];
    }
  }
  return undefined;
};

				
			

2. Function Methods (Call, Apply, Bind)

Function.call

Invokes a function with a specified this context and arguments.

				
					<!--JavaScript-->

Function.prototype.myCall = function(context = {}, ...args) {
  // 1. Assign the function (this) to the context object
  context.fn = this;
  
  // 2. Execute the function
  const result = context.fn(...args);
  
  // 3. Delete the property to clean up
  delete context.fn;
  return result;
};

				
			

Function.apply

Same as call, but arguments are passed as an array.

				
					<!--JavaScript-->

Function.prototype.myApply = function(context = {}, args = []) {
  if (!Array.isArray(args)) throw new Error("Args must be array");
  context.fn = this;
  const result = context.fn(...args);
  delete context.fn;
  return result;
};

				
			

Function.bind

Returns a new function with this permanently bound.

				
					<!--JavaScript-->

Function.prototype.myBind = function(context, ...args1) {
  const fn = this;
  return function(...args2) {
    // Combine initial arguments and new arguments
    return fn.apply(context, [...args1, ...args2]);
  };
};



				
			

3. Promise Polyfills (Async Logic)

Promise.all

Waits for all promises to resolve. If one fails, it rejects immediately.

				
					<!--JavaScript-->

Promise.myAll = function(promises) {
  return new Promise((resolve, reject) => {
    let results = [];
    let completed = 0;

    promises.forEach((p, index) => {
      // Promise.resolve wraps non-promises (e.g., numbers)
      Promise.resolve(p).then((value) => {
        results[index] = value;
        completed++;
        if (completed === promises.length) {
          resolve(results);
        }
      }).catch((err) => reject(err)); // Fail fast
    });
  });
};

				
			

Promise.allSettled

Waits for all to finish, regardless of success or failure.

				
					<!--JavaScript-->

Promise.myAllSettled = function(promises) {
  return new Promise((resolve) => {
    let results = [];
    let completed = 0;

    promises.forEach((p, index) => {
      Promise.resolve(p)
        .then((value) => {
          results[index] = { status: 'fulfilled', value };
        })
        .catch((reason) => {
          results[index] = { status: 'rejected', reason };
        })
        .finally(() => {
          completed++;
          if (completed === promises.length) resolve(results);
        });
    });
  });
};



				
			

Promise.race

Returns the first promise that settles (resolves or rejects).

				
					<!--JavaScript-->

Promise.myRace = function(promises) {
  return new Promise((resolve, reject) => {
    promises.forEach(p => {
      Promise.resolve(p).then(resolve).catch(reject);
    });
  });
};

				
			

Promise.any

Returns the first fulfilled promise. If all fail, returns an AggregateError.

				
					<!--JavaScript-->

Promise.myAny = function(promises) {
  return new Promise((resolve, reject) => {
    let errors = [];
    let rejectedCount = 0;
    promises.forEach((p, index) => {
      Promise.resolve(p).then(resolve).catch(err => {
        errors[index] = err;
        rejectedCount++;
        if (rejectedCount === promises.length) {
          reject(new AggregateError(errors, "All promises rejected"));
        }
      });
    });
  });
};



				
			

Promise.prototype.finally

Runs code regardless of promise outcome (good for cleanup).

				
					<!--JavaScript-->

Promise.prototype.myFinally = function(callback) {
  return this.then(
    (value) => Promise.resolve(callback()).then(() => value),
    (err) => Promise.resolve(callback()).then(() => { throw err; })
  );
};

				
			

4. Performance & Optimization

Debounce

Only run the function after the user stops doing the action for d milliseconds. (e.g., Search bar).

				
					<!--JavaScript-->

function myDebounce(fn, delay) {
  let timer;
  return function(...args) {
    if (timer) clearTimeout(timer); // Clear previous timer
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

				
			

Throttle

Ensure function only runs at most once every d milliseconds. (e.g., Resize window).

				
					<!--JavaScript-->

function myThrottle(fn, delay) {
  let lastRan = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastRan > delay) {
      fn.apply(this, args);
      lastRan = now;
    }
  };
}

				
			

Memoization

Cache the result of a function call.

				
					<!--JavaScript-->

function myMemoize(fn) {
  const cache = {};
  return function(...args) {
    // Create a unique key based on arguments
    const key = JSON.stringify(args);
    
    if (cache[key]) {
      console.log("Fetching from cache...");
      return cache[key];
    } else {
      const result = fn.apply(this, args);
      cache[key] = result;
      return result;
    }
  };
}

				
			

5. Advanced & Utilities

Deep Copy

Creates a complete duplicate of an object (nested objects included).

				
					<!--JavaScript-->

function deepClone(obj) {
  // Handle primitives and null
  if (obj === null || typeof obj !== 'object') return obj;
  
  // Handle Array vs Object
  const clone = Array.isArray(obj) ? [] : {};

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // Recursively clone children
      clone[key] = deepClone(obj[key]);
    }
  }
  return clone;
 }

				
			

Flatten Deeply Nested Object

Convert { a: { b: { c: 1 } } } to { “a.b.c”: 1 }.

				
					<!--JavaScript-->

function flattenObject(obj, parentKey = '', result = {}) {
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // Create new key name (e.g., "user.address.city")
      const newKey = parentKey ? `${parentKey}.${key}` : key;

      if (typeof obj[key] === 'object' && obj[key] !== null) {
        flattenObject(obj[key], newKey, result);
      } else {
        result[newKey] = obj[key];
      }
    }
  }
  return result;
}

				
			

Event Emitter (Pub/Sub)

A simple system to subscribe to events and emit them.

				
					<!--JavaScript-->

class EventEmitter {
  constructor() {
    this.events = {}; // Storage for events
  }

  on(eventName, listener) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(listener);
  }

  emit(eventName, ...args) {
    if (this.events[eventName]) {
      this.events[eventName].forEach(listener => listener(...args));
    }
  }

  off(eventName, listenerToRemove) {
    if (!this.events[eventName]) return;
    this.events[eventName] = this.events[eventName].filter(
      l => l !== listenerToRemove
    );
  }
}



				
			

setInterval Polyfill

Implementing setInterval using setTimeout.

				
					<!--JavaScript-->

function mySetInterval(callback, delay) {
  let timerId = { flag: true }; // Ref object to control stopping
  
  function loop() {
    if (!timerId.flag) return; // Stop if cleared
    callback();
    setTimeout(loop, delay); // Recursively call
  }
  
  setTimeout(loop, delay);
  return timerId;
}

function myClearInterval(timerId) {
  timerId.flag = false;
}

				
			

Async Retry

Retries a promise-based function N times if it fails.

				
					<!--JavaScript-->

function retry(fn, retries, delay) {
  return new Promise((resolve, reject) => {
    fn()
      .then(resolve)
      .catch((err) => {
        if (retries === 0) {
          reject(err);
        } else {
          setTimeout(() => {
            console.log(`Retrying... (${retries} left)`);
            retry(fn, retries - 1, delay).then(resolve).catch(reject);
          }, delay);
        }
      });
  });
}

				
			

MapLimit (Parallel Limit)

Run async tasks for an array of inputs, but only limit tasks at a time.

				
					<!--JavaScript-->

async function mapLimit(inputs, limit, iterateeFn) {
  const results = [];
  const executing = []; // Currently running promises

  for (const item of inputs) {
    // Create the promise
    const p = Promise.resolve().then(() => iterateeFn(item));
    results.push(p);

    // Keep track of executing promises
    const e = p.then(() => executing.splice(executing.indexOf(e), 1));
    executing.push(e);

    // If we hit the limit, wait for one to finish
    if (executing.length >= limit) {
      await Promise.race(executing);
    }
  }
  return Promise.all(results);
}
				
			

💡 Interview Tip

For the Promise polyfills and MapLimit, the interviewer usually looks for:

  1. Correct handling of concurrency (Are you actually waiting?).
  2. Error handling (What if a promise rejects?).
  3. Edge cases (Empty arrays, non-promise inputs).

Learn how JavaScript works internally, including the engine, call stack, and memory management — click here

Recommended External Resources

Leave a Reply

Your email address will not be published. Required fields are marked *