Polyfill - call, apply & bind

Published: (January 10, 2026 at 09:50 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

ZeeshanAli-0704

I’ll provide the polyfill code for each method with a brief explanation in separate sections. The focus is on simplicity and clarity so you can easily explain them during an interview.

1. Polyfill for call()

Code

// Polyfill for Function.prototype.call
if (!Function.prototype.customCall) {
  Function.prototype.customCall = function (currentThis = {}, ...args) {
    // Check if 'this' is a callable function
    if (typeof this !== 'function') {
      throw new Error(`${this} is not a function`);
    }
    // Attach the function to the provided context
    currentThis.tempFn = this;
    // Call the function with the arguments and return result
    const result = currentThis.tempFn(...args);
    // Clean up the temporary property
    delete currentThis.tempFn;
    return result;
  };
}

// Example usage
const obj = { name: 'John' };
function greet(message) {
  return `${message}, ${this.name}!`;
}
console.log(greet.customCall(obj, 'Hello')); // Outputs: Hello, John!

Explanation

  • Purpose: call() invokes a function with a specified this context and individual arguments. It’s often used for function borrowing.
  • How it works: The polyfill temporarily attaches the function (this) to the provided context (currentThis), calls it with the spread arguments (...args), then removes the temporary property to avoid polluting the object.
  • Key interview point: call() passes arguments individually (unlike apply()) and executes the function immediately. The error check ensures this is a function.
  • Limitation: This basic version doesn’t handle edge cases such as null/undefined contexts, which in a full implementation would default to the global object.

2. Polyfill for apply()

Code

// Polyfill for Function.prototype.apply
if (!Function.prototype.customApply) {
  Function.prototype.customApply = function (currentThis = {}, args = []) {
    // Check if 'this' is a callable function
    if (typeof this !== 'function') {
      throw new Error(`${this} is not a function`);
    }
    // Check if args is an array
    if (!Array.isArray(args)) {
      throw new Error('Arguments must be an array');
    }
    // Attach the function to the provided context
    currentThis.tempFn = this;
    // Call the function with the array of arguments and return result
    const result = currentThis.tempFn(...args);
    // Clean up the temporary property
    delete currentThis.tempFn;
    return result;
  };
}

// Example usage
const obj = { name: 'Jane' };
function greet(message, punctuation) {
  return `${message}, ${this.name}${punctuation}`;
}
console.log(greet.customApply(obj, ['Hi', '!'])); // Outputs: Hi, Jane!

Explanation

  • Purpose: apply() works like call(), but it accepts arguments as an array. This is handy when the number of arguments is dynamic.
  • How it works: After validating that this is a function and that args is an array, the polyfill temporarily attaches the function to the context, spreads the array into arguments, and then cleans up.
  • Key interview point: Emphasize that apply() takes an array of arguments, making it useful for scenarios such as passing the arguments object or spreading an array of parameters.
  • Limitation: The implementation assumes args is always provided; a full polyfill would also handle null or non‑array inputs gracefully.

3. Polyfill for bind()

Code

// Polyfill for Function.prototype.bind
if (!Function.prototype.customBind) {
  Function.prototype.customBind = function (currentThis, ...boundArgs) {
    // Check if 'this' is a callable function
    if (typeof this !== 'function') {
      throw new Error(`${this} is not a function`);
    }
    // Store the original function
    const originalFn = this;
    // Return a new function that can be invoked later
    return function (...callArgs) {
      // Call the original function with bound context and combined arguments
      return originalFn.customApply(currentThis, boundArgs.concat(callArgs));
    };
  };
}

// Example usage
const obj = { name: 'Alice' };
function greet(message) {
  return `${message}, ${this.name}!`;
}
const boundGreet = greet.customBind(obj, 'Hey');
console.log(boundGreet());               // Outputs: Hey, Alice!
console.log(boundGreet('Hello'));        // Outputs: Hey, Alice! (ignores extra args)

Explanation

  • Purpose: bind() creates a new function with a fixed this context and optionally preset arguments. It does not execute immediately; the returned function can be called later.
  • How it works: The polyfill captures the original function and any bound arguments, then returns a wrapper that merges those with any arguments supplied at call time. It uses customApply to invoke the original function with the fixed context.
  • Key interview point: Stress that bind() is for delayed execution and permanent context binding (e.g., for event handlers). Explain how it merges preset and new arguments.
  • Limitation: This version relies on customApply for simplicity and does not handle constructor usage (new) or other edge cases that a complete polyfill would need to address.

Unbound Calls

General Interview Talking Points

Why Polyfills?

Explain that polyfills like these ensure compatibility with older browsers that lack native support for call(), apply(), or bind().

  • Performance – Native implementations are faster.
  • Completeness – Polyfills fill gaps in environments where the methods are missing.

Common Theme

All three methods manipulate the this context, a core concept in JavaScript.

  • Essential for functional‑programming patterns such as method borrowing.

Testing

  • Test the polyfills across different environments (e.g., IE 11, older mobile browsers).
  • In production, consider using a battle‑tested library like core‑js, which covers many edge cases.

Browser Compatibility

Back to Blog

Related posts

Read more »

Polyfill - useState (React)

!ZeeshanAli-0704https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fupload...