DEV Community

Rizwan C
Rizwan C

Posted on

Mastering call, apply, and bind

Understanding call, apply, and bind is essential if you want to truly master this (JavaScript function context).

In JavaScript, the value of this depends on how a function is called, not where it is defined.

const user = {
  name: "Jon",
  job: "engineer",
  intro() {
    console.log(`${this.name} is ${job}`);
  }
};

user.intro(); // Jon is engineer
Enter fullscreen mode Exit fullscreen mode

But what if we want to use greet for another object?

That’s where call, apply, and bind come in.

  • call() - invokes function immediately and allows you to pass arguments individually.
  • apply() - similar to call(), but it accepts arguments as an array.
  • bind() - Unlike call and apply, bind() does NOT execute immediately. It returns a new function with this permanently bound.

call()

call() method invokes a function immediately. It takes the object you want to use as this as the first argument, followed by individual arguments for the function.

const user1 = { name: "Jon" };
const user2 = { name: "Ron" };

function intro(job) {
  console.log(`${this.name} is ${this.job}`);
}

intro.call(user1, "engineer");   // Jon is engineer
intro.call(user2, "teacher");   // Ron is teacher
Enter fullscreen mode Exit fullscreen mode

apply()

apply() is similar to call(), The only difference is how it handles arguments: it takes them as an array instead of one by one.

function greet(city, country) {
  console.log(this.name + " is from " + city + ", " + country);
}

greet.apply(user1, ["Paris", "France"]); // "Jon is from Paris, France"
Enter fullscreen mode Exit fullscreen mode

bind()

Unlike the other two, bind does not invoke the function immediately. Instead, it returns a new function with this permanently bound to the provided object

const jonIntro = intro.bind(user1, "engineer");

jonIntro(); // Jon is engineer
Enter fullscreen mode Exit fullscreen mode

Polyfill for call, apply and bind

call()

Function.prototype.myCall = function (context, ...args) {
    context = context ?? globalThis;
    context = Object(context);

    const uniqueKey = Symbol();

    context[uniqueKey] = this;
    const result = context[uniqueKey](...args);

    delete context[uniqueKey];
    return result;
};

intro.myCall(user1, "engineer");   // Jon is engineer
Enter fullscreen mode Exit fullscreen mode

apply()

Function.prototype.myApply = function (context, args = []) {
    context = context ?? globalThis;
    context = Object(context);

    const uniqueKey = Symbol();

    context[uniqueKey] = this;
    const result = context[uniqueKey](...args);

    delete context[uniqueKey];
    return result;
};

greet.myApply(user1, ["Paris", "France"]); // "Jon is from Paris, France"
Enter fullscreen mode Exit fullscreen mode

bind()

Function.prototype.myBind = function (context, ...args) {
    const fn = this;

    return function (...newArgs) {
        return fn.apply(context, [...args, ...newArgs]);
    };
};

const jonIntro = intro.myBind(user1, "engineer");
jonIntro(); // Jon is engineer
Enter fullscreen mode Exit fullscreen mode

Top comments (0)