DAMO'S BLOG

Remote Full-Stack Engineer | Supports North America/Europe Time Zones

Call, Apply, and Bind

In JavaScript, call, apply, and bind are three methods of function objects, all used to explicitly set the this value (i.e., change the context) when a function is invoked. Although their functionality is similar, they differ in how they are called and how arguments are passed.

1.call

syntax:

func.call(thisArg, arg1, arg2, ...)

Features:

  • Immediately invokes the function.
  • Arguments are passed in as a comma-separated list.

Manual implementation example:

Function.prototype.Call = function(context, ...args) {
  // 1. Type check
  if (typeof this !== 'function') {
    throw new TypeError(this + ' is not a function');
  }

  // 2. Handle null/undefined context
  if (context == null) {
    context = globalThis;
  } else {
    // 3. Wrap primitive values into objects
    context = Object(context);
  }

  // 4. Create a Symbol to avoid property name collisions with existing keys on `context`
  const fn = Symbol();

  // 5. Temporarily attach the function (`this`) to `context`
  // Here, `this` refers to the function on which `Call` is being invoked
  context[fn] = this;

  // 6. Execute the function
  const result = context[fn](...args);

  // 7. Remove the temporarily attached function
  delete context[fn];

  return result;
};

2.apply

syntax:

func.apply(thisArg, [argsArray])

Features:

  • Immediately invokes the function.
  • The second argument is an array (or array-like object) used to pass arguments.

Manual implementation example:

Function.prototype.Applay = function(context, args) {
  // 1. Type check
  if (typeof this !== 'function') {
    throw new TypeError(this + ' is not a function');
  }

  // 2. Handle null/undefined context
  if (context == null) {
    context = globalThis;
  } else {
    // 3. Wrap primitive values into objects
    context = Object(context);
  }

  // 4. Create a Symbol to avoid property name collisions with existing keys on `context`
  const fn = Symbol();

  // 5. Temporarily attach the function (`this`) to `context`
  // Here, `this` refers to the function on which `Applay` is being invoked
  context[fn] = this;

  // 6. Execute the function, spreading the `args` array as arguments
  const result = context[fn](...args);

  // 7. Remove the temporary property
  delete context[fn];

  return result;
};

Tip: When you have a set of arguments stored in an array and want to pass them to a function, apply is very convenient. However, since ES6, you can also use the spread operator with call:greet.call(person, …['Hi', '.']);

3. bind

syntax:

const newFunc = func.bind(thisArg, arg1, arg2, ...);

Features:

  • Does not execute immediately; instead, it returns a new function whose this value is permanently bound to the specified object.
  • Supports partial application of arguments (currying / partial function application).

Manual implementation example:

Function.prototype.Bind = function(context, ...contextArgs) {
  // 1. Type check
  if (typeof this !== 'function') {
    throw new TypeError(this + ' is not a function');
  }

  // 2. Store the function on which Bind is called
  const fn = this;

  // 3. Handle null/undefined context
  if (context == null) {
    context = globalThis;
  } else {
    // 4. Wrap primitive values into objects
    context = Object(context);
  }

  const boundFunction = function(...args) {
    // 5. Determine the `this` value:
    // If called with `new`, `this` refers to the newly created instance;
    // otherwise, use the bound `context`.
    const thisArg = this instanceof fn ? this : context;
    return fn.apply(thisArg, contextArgs.concat(args));
  };

  // 6. If the original function has a prototype, ensure the bound function inherits it
  if (fn.prototype) {
    boundFunction.prototype = Object.create(fn.prototype);
  }

  return boundFunction;
};

⚠️ Note: The new function returned by bind will ignore any subsequent attempts to change its this value using call or apply, because its this has already been permanently (hard) bound.

Comparison Summary

MethodExecutes Immediately?Argument FormatReturn ValuePrimary Use Case
call✅ YesIndividual argumentsResult of executionTemporarily change this and invoke the function
apply✅ YesArguments as an arrayResult of executionInvoke with this changed, when args are in an array
bind❌ NoIndividual args (can be partially applied)New bound functionCreate a new function with a fixed this context

Real-World Use Cases

  • Borrowing methods: e.g., converting array-like objects to real arrays using
    Array.prototype.slice.call(arguments).
  • Event handling: preserving the correct this in callbacks, such as
    btn.addEventListener('click', handler.bind(this)).
  • Function currying: pre-filling some arguments with bind to create more specialized functions.

Reflection Questions (a.k.a. “Looking for trouble”)

Question 1:
Why does the implementation of bind need to consider prototype chain inheritance, while call and apply do not?

Question 2:
Why can’t the this value of a function returned by bind be overridden by subsequently using call or apply?

Tags:

Leave a Reply

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

*
*

Tech Stack

Nestjs,PHP,Angular,React,Vue

Contact Me

地址
123 Main Street
New York, NY 10001

营业时间
星期一—五:9:00–17:00
星期六—日:11:00–15:00