JavaScript Call Apply Bind

Control the this keyword explicitly using call, apply, and bind on any function.

TL;DR

  1. 01call() and apply() invoke a function with a chosen this value.
  2. 02apply() takes arguments as an array; call() takes a list.
  3. 03bind() returns a new function with this permanently fixed.

Tips

  1. 01Use bind() when passing a method as a callback or event handler, so this stays correct.
  2. 02Reach for apply() when arguments already exist as an array, such as forwarding arguments between wrapper functions.

Warnings

  1. 01Calling bind() repeatedly on the same function creates a new wrapper each time, which breaks reference equality checks like removeEventListener.
  2. 02Arrow functions ignore call, apply, and bind for this, since arrow functions always inherit this from their enclosing scope.

Why this Needs Explicit Control

    Call site matters

    The value of this depends on how a function is called, not where it's defined.

    const user = { name: 'Ada', greet() { return `Hi, ${this.name}`; } };
    const fn = user.greet;
    fn(); // 'Hi, undefined' — this lost its connection to user
    Detached methods

    Passing a method as a value, like a callback, detaches it from its original object.

    Explicit control

    call, apply, and bind exist to set this explicitly regardless of call site.

    Function.prototype

    All three live on Function.prototype, so every function has access to them.

    Common breakage

    Without explicit control, callbacks and event handlers commonly break on this.

    Legacy code

    Understanding these three methods is essential for working with older, non-arrow-function code.

Using call()

    call(thisArg, ...args)

    Invoke a function immediately with arguments listed individually.

    function greet(greeting) { return `${greeting}, ${this.name}`; }
    greet.call({ name: 'Ada' }, 'Hi'); // 'Hi, Ada'
    First argument is this

    The first argument becomes this inside the function for that one call.

    Positional arguments

    Remaining arguments map positionally to the function's parameters.

    Borrowing methods

    Use call() to borrow a method from one object and run it against another.

    const max = Math.max.call(null, 1, 5, 3); // 5
    null or undefined

    Passing null or undefined as thisArg uses the global object in non-strict mode.

    Single invocation only

    call() does not change the original function; it only affects that single invocation.

Using apply()

    apply(thisArg, argsArray)

    Works exactly like call(), but arguments are passed as one array.

    function sum(a, b, c) { return a + b + c; }
    sum.apply(null, [1, 2, 3]); // 6
    Array-like arguments

    apply() is the better choice when arguments already exist as an array or array-like.

    Math.max.apply(null, [4, 8, 2]); // 8
    Spread replaces it

    Modern code often replaces apply() with the spread operator: Math.max(...nums).

    Forwarding arguments

    apply() still matters when forwarding an arguments object between functions.

    Synchronous return

    Both call() and apply() execute the function synchronously and return its result.

    Choosing between them

    Choosing between call and apply is purely about argument shape — list versus array.

Using bind()

    bind(thisArg)

    Creates a new function with this permanently fixed to the given value.

    const user = { name: 'Ada', greet() { return `Hi, ${this.name}`; } };
    const boundGreet = user.greet.bind(user);
    boundGreet(); // 'Hi, Ada' — works even detached from user
    Doesn't invoke

    Unlike call() and apply(), bind() does not invoke the function immediately.

    Store for later

    The returned function can be stored, passed around, and called later safely.

    Bind in constructors

    Bind methods in a constructor so they keep this when used as callbacks.

    class Button {
      constructor() { this.onClick = this.onClick.bind(this); }
      onClick() { console.log(this); }
    }
    Fixed permanently

    Calling bind() again on an already-bound function cannot change its fixed this.

    Bound function names

    Bound functions report 'bound functionName' when inspected, which helps when debugging.

Partial Application with bind

    Prepended arguments

    Arguments passed to bind() after thisArg get permanently prepended to every future call.

    function multiply(a, b) { return a * b; }
    const double = multiply.bind(null, 2);
    double(5); // 10
    Partial application

    This technique is called partial application, fixing some arguments ahead of time.

    Event handler context

    Combine partial application with event handlers to pass extra context cleanly.

    button.addEventListener('click', handleClick.bind(null, itemId));
    Extra arguments still work

    Partially applied functions still accept additional arguments at call time.

    Specialized utilities

    Use partial application to build specialized utility functions from general ones.

    Avoids wrappers

    This pattern avoids writing repetitive wrapper functions for common argument combinations.

In Practice

FAQ