completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

call, apply & bind

Learn how call, apply, and bind set this explicitly, pass arguments, borrow methods, create partial applications, and build a simplified bind helper.

By the end, you can
  • 01
    Choose call, apply, or bindPick call to run a function now with arguments listed one by one, apply to run it now with an array, or bind to make a new function for later.
  • 02
    Borrow a methodRun an array or object method on another value that has what the method needs, such as arguments or a string.
  • 03
    Write a small bind helperWrite myBind, which works like the built-in bind for normal calls, using apply, rest parameters, and spread.

Choosing this yourself

In the last lesson, The this keyword, you learned that this is the object a function works on. You also learned four rules that decide what this is. One of those rules lets you choose this yourself. This lesson is about that rule.

Functions in JavaScript are objects, so they have methods too. A method is a function stored on an object. Every function has three methods for choosing this:

  • call runs the function now, with the this you choose.
  • apply also runs the function now. It takes the other arguments inside one array.
  • bind does not run the function. It makes a new function that remembers your this for later.

None of the three changes the original function. They only decide how one call runs.

Real-life analogyA friend's phone for one call

You borrow your friend Ada's phone to make one call. When the call ends, you give the phone back. Using the phone with a list of what to say is the same, just read from a list. Saving Ada on speed dial is different: nothing happens now, but Ada is ready the moment you tap later.

In real life: Use Ada's phone for one call
In JavaScript: introduce.call(ada, "Hello", "!")
In real life: Use Ada's phone and read your words from a list
In JavaScript: introduce.apply(ada, ["Hello", "!"])
In real life: Save Ada on speed dial
In JavaScript: introduce.bind(ada) returns a new function
Definition

call, apply, and bind are methods that every function has. Functions get them from Function.prototype, the shared object that holds the methods of all functions. They let you run a regular function with a this value that you pick. bind can also save some arguments for later.

There is one exception. An arrow function, written () => ..., has no this of its own. It uses the this of the code around it.

call can't change this for an arrow functionPop out in the code editor (opens in a new tab)JavaScript
function makeGreeter() {
  const greet = () => this.name;
  return greet;
}

const ada = { name: "Ada" };
const greetAda = makeGreeter.call(ada);
console.log(greetAda.call({ name: "Grace" }));

Line 2 makes an arrow function inside makeGreeter. The arrow uses the same this as makeGreeter. Line 7 runs makeGreeter with call, so its this is ada. Line 8 tries to run the arrow with Grace as this. It still prints Ada. So call, apply, and bind can't change this for an arrow function.

You will also borrow methods from built-in objects, and write a small myBind function of your own. Two later lessons go deeper: Currying & partial application and Polyfill call, apply & bind. This lesson covers what each method does and when to use it.

call and apply run the function now

INTERACTIVE

call and apply are almost the same. Both run the function right away. For both, the first argument is the value to use as this. The only difference is how you pass the other arguments:

  • call takes them one by one, with commas: introduce.call(ada, "Hello", "!").
  • apply takes them inside one array: introduce.apply(ada, ["Hello", "!"]).

An easy way to remember: apply and array both start with "a".

The table compares all three methods. Read across a row to see what one method does.

call, apply, and bind side by side
MethodWhen does it run, and what do you get back?How do you pass the arguments?
callIt runs now. You get back the function's result.You list them one by one, with commas.
applyIt runs now. You get back the function's result.You put them all in one array.
bindIt doesn't run now. You get back a new function to call later.You list the ones to save, one by one.

Try it below. The function introduce reads this.name. Pick a method and an object. The last line of the code is what you would type in the console. The result comes from running real JavaScript.

Try call, apply, and bind
The code you would typePop out in the code editor (opens in a new tab)JavaScript
function introduce(greeting, punctuation) {  return `${greeting}, I'm ${this.name}${punctuation}`;} const ada = { name: "Ada" };const grace = { name: "Grace" };const linus = { name: "Linus" }; introduce.call(ada, "Hello", "!");
Resultcall
this isAda
Returned valueHello, I'm Ada!
The callintroduce.call(ada, "Hello", "!")
Try it yourself

call runs introduce now with the object you picked as this. The other arguments are listed one by one.

Change the method and the object. The result comes from running the real function in this lesson.

The result depends on how you call introduce, not on where it was written. introduce.call(ada, "Hello", "!") means: "Run introduce now, and inside it, make this be ada." The apply version means the same thing. It just takes ["Hello", "!"] as one array.

Step through the code below. Line 8 uses call and line 9 uses apply.

Run introduce with call and apply
Step 0 of 5Ready
Your turn: follow the blue line

Guess each result before you step. call and apply both run the function right away. Only the way you pass the arguments is different.

Running in
  1. script
Next: line 1
  return `${greeting}, I'm ${this.name}${punctuation}`;} const ada = { name: "Ada" };const grace = { name: "Grace" }; introduce.call(ada, "Hello", "!");introduce.apply(grace, ["Hi", "."]);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Top: introduce.call(ada, "Hello", "!"). The box called this holds ada. Two separate cards, "Hello" and "!", are the arguments. An arrow leads to the result "Hello, I'm Ada!". Bottom: introduce.apply(grace, ["Hi", "."]). The box called this holds grace. One array card holds the arguments. An arrow leads to the result "Hi, I'm Grace.".introduce.call(ada, "Hello", "!")adathis"Hello""!"two arguments"Hello, I'm Ada!"returned nowintroduce.apply(grace, ["Hi", "."])gracethis["Hi", "."]one array"Hi, I'm Grace."returned now
Both lines run introduce right away. The first value you pass goes into this. call takes the other arguments one by one. apply takes them inside one array.

The spread syntax, ...numbers, also takes the items out of an array and passes them one by one. Math.max returns the largest number you pass to it.

apply and spread both pass an array's itemsPop out in the code editor (opens in a new tab)JavaScript
const numbers = [4, 9, 2];
console.log(Math.max.apply(null, numbers));
console.log(Math.max(...numbers));

const argumentBag = { 0: 4, 1: 9, 2: 2, length: 3 };
console.log(Math.max.apply(null, argumentBag));

Lines 2 and 3 both print 9. When you have a real array, spread is easier to read.

Line 5 makes an array-like object. It has numbered keys (0, 1, 2) and a length, but it is not a real array. Line 6 shows that apply accepts it too, and prints 9. Spread would throw an error here, because a plain object can't be spread into arguments.

bind makes a new function for later

STEP THROUGH

bind does not run the function. It returns a new function. The new function remembers the this you gave it. It can also remember the first few arguments.

Saving some arguments now and giving the rest later has a name: partial application.

Real-life analogyA saved contact

You save Ada as a contact before you need to call her. Later you tap her name, and the phone already knows who to call. A form with the first blank already filled in works the same way: you only fill in the rest.

In real life: Save Ada as a contact
In JavaScript: introduce.bind(ada) keeps this as Ada
In real life: Fill in the first blank on a form ahead of time
In JavaScript: multiply.bind(null, 2) saves the first argument
In real life: Tap the saved contact later
In JavaScript: Call the new function later, for example from a timer

Step through the code below. It shows what the new function from bind can and can't do. A function made by bind is called a bound function.

What a bound function can and can't do
Step 0 of 11Ready
Your turn: follow the blue line

Step through the facts that make bind different from call and apply.

Running in
  1. script
Next: line 1
  return `${greeting}, I'm ${this.name}${punctuation}`;}function multiply(a, b) {  return a * b;} const ada = { name: "Ada" };const grace = { name: "Grace" };const adaIntro = introduce.bind(ada, "Hello");const double = multiply.bind(null, 2); adaIntro.call(grace, "!");double === multiply;double(5);double.name;double.length; function Person(name) {  this.name = name;}const BoundPerson = Person.bind({ name: "Ignored" });const student = new BoundPerson("Maya");student.name;
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Pick a question to answer before you step

Watch line 13: this stays ada.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Two lines matter most. Line 10 makes the bound function adaIntro:

const adaIntro = introduce.bind(ada, "Hello"). The introduce function card is not run. An arrow labeled bind leads to a new cart called adaIntro. The cart holds two cards: this: ada, and "Hello".const adaIntro = introduce.bind(ada, "Hello")introducenot runbindthis: ada"Hello"adaIntronew function
Line 10 does not run introduce. bind makes a new function, adaIntro. It remembers two things for later: this is ada, and the first argument is "Hello".

Line 13 calls adaIntro with call and a different object:

adaIntro.call(grace, "!"). The grace card is marked ignored. The "!" card has an arrow into the adaIntro cart, which still holds this: ada and "Hello". An arrow from the cart leads to the result "Hello, I'm Ada!". Under the result: this = ada.adaIntro.call(grace, "!")graceignored"!"addedthis: ada"Hello"adaIntro"Hello, I'm Ada!"this = ada
Line 13 tries to pass grace as this. The bound function ignores it and keeps ada. The "!" is still used: it is added after the saved "Hello".

The code also shows a few facts about bound functions:

  • A bound function is a different function from the original. Line 14 prints false.
  • Line 15 runs double(5). That really runs multiply(2, 5), so it gives 10.
  • Its name starts with "bound ". Line 16 gives "bound multiply".
  • Its length is the number of arguments it still expects. Each saved argument takes one off. Line 17 gives 1.
  • If you call it with new, the new object becomes this, and the saved this is ignored. Lines 23 and 24 show this.

Here is partial application in a small, real task. formatPrice needs a currency sign and an amount. toFixed(2) turns a number into text with two digits after the dot.

Save the currency sign with bindPop out in the code editor (opens in a new tab)JavaScript
function formatPrice(currency, amount) {
  return currency + amount.toFixed(2);
}

const formatDollars = formatPrice.bind(null, "$");
console.log(formatDollars(3));

Line 5 saves "$" as the first argument. formatPrice doesn't use this, so we pass null for it. Line 6 gives only the amount, 3, and prints $3.00. The part that stays the same is saved. The part that changes comes later.

Use bind when a function will be called later, for example by a timer, and it must keep its object or a fixed first argument. Don't bind every function just in case. Two other tools are sometimes clearer:

  • A small wrapper function that calls the original. It is easier to read when you need extra steps around the call.
  • An arrow function, when you want it to use the this of the code around it.
A quick choice

Use bind for a function you'll reuse with a fixed object or fixed first arguments. Use a wrapper function when you need extra steps around the call. Use an arrow function when you want the this of the code around it.

Borrowing a method from another object

STEP THROUGH

Sometimes your value doesn't have the method you need, but another kind of object does. Method borrowing means running that other method on your value, with call or apply. It works when your value has what the method needs.

Arrays get methods like slice and join from Array.prototype, the shared object that holds the methods of all arrays. You can take a method from there and run it on another value.

In the Iterating arrays lesson you met array-like values: objects with numbered items and a length, but no array methods. arguments is one of them. It is a list of all the values passed to a regular function.

Real-life analogyBorrowing a friend's phone

Your friend's phone can make one call for you. It doesn't become your phone. You can use it because you have what a call needs: a number to dial.

In real life: You have a phone number but no phone
In JavaScript: arguments has numbered items but no array methods
In real life: Use your friend's phone once
In JavaScript: Array.prototype.slice.call(arguments)
In real life: Give the phone back
In JavaScript: The method runs once; nothing is added to arguments

Step through the code below. Each line borrows a method in a different way.

Borrow methods from arrays and objects
Step 0 of 8Ready
Your turn: follow the blue line

Method borrowing means running a method from one kind of value on another value that has what the method needs.

Running in
  1. script
Next: line 1
  const args = Array.prototype.slice.call(arguments);  return args.join(" | ");} const letters = Array.prototype.join.call("abc", "-");const nums = [4, 9, 2];const biggestOld = Math.max.apply(null, nums);const biggestNow = Math.max(...nums);const hasName = Object.prototype.hasOwnProperty.call({ name: "Ada" }, "name");const hasNameModern = Object.hasOwn({ name: "Ada" }, "name");collect("red", "green", "blue");
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
join works on an object with numbered itemsPop out in the code editor (opens in a new tab)JavaScript
const tags = { 0: "red", 1: "green", 2: "blue", length: 3 };
const joined = Array.prototype.join.call(tags, " | ");
console.log(joined);

Line 1 makes an array-like object. It has numbered keys and a length, but it is not an array. Line 2 borrows join from arrays and runs it with tags as this. Line 3 prints red | green | blue.

Array.prototype.join.call(tags, " | "). The join function card, an array method, is borrowed. An arrow leads to the tags cart, which is not an array. It holds red, green, and blue. An arrow from the cart leads to the printed result: red | green | blue.Array.prototype.join.call(tags, " | ")joinarray methodborrowedredgreenbluetagsnot an arrayred | green | blueprinted
tags is a plain object, not an array, so it has no join of its own. call runs the array's join once with tags as this. join only needs numbered items and a length, and tags has both.

A borrowed method only works if your value has the properties the method reads. join reads numbered items and length, so tags works.

Newer JavaScript has easier ways to do two of these jobs:

  • Math.max(...nums) instead of Math.max.apply(null, nums).
  • Object.hasOwn(obj, key) instead of Object.prototype.hasOwnProperty.call(obj, key). Both check whether obj has its own property called key.

You will still see the older, borrowed versions in a lot of existing code, so it helps to know how they work.

Writing your own bind

STEP THROUGH

A polyfill is code that adds a built-in feature to browsers that don't have it yet. A real polyfill for bind would add a method to Function.prototype, so every function gets it. That changes every function on the page, so here we write a plain function instead: myBind(fn, thisArg, ...preset).

It takes three things:

  • fn: the function to bind.
  • thisArg: the value to use as this.
  • ...preset: the arguments to save. The ... collects all the remaining arguments into one array called preset.
A small bind helperPop out in the code editor (opens in a new tab)JavaScript
function myBind(fn, thisArg, ...preset) {
  return function boundFunction(...args) {
    return fn.apply(thisArg, [...preset, ...args]);
  };
}

function introduce(greeting, punctuation) {
  return `${greeting}, I'm ${this.name}${punctuation}`;
}

const ada = { name: "Ada" };
const sayHello = myBind(introduce, ada, "Hello");
sayHello("!");

In plain words, line by line:

  1. Line 1: myBind takes the function, the this value, and the arguments to save.
  2. Line 2: it returns a new function, boundFunction. Nothing runs yet. The new function remembers fn, thisArg, and preset.
  3. Line 3: when boundFunction runs later, it calls fn with apply. It uses thisArg as this. It puts the saved arguments first and the new ones after.

Line 12 makes sayHello with ada and "Hello" saved. Line 13 calls it with "!" and gets "Hello, I'm Ada!". The built-in bind gives the same result.

Build a small myBind
Step 0 of 5Ready
Your turn: follow the blue line

This is a small helper. It doesn't do everything the built-in bind does.

Running in
  1. script
Next: line 1
  return function boundFunction(...args) {    return fn.apply(thisArg, [...preset, ...args]);  };} function introduce(greeting, punctuation) {  return `${greeting}, I'm ${this.name}${punctuation}`;} const ada = { name: "Ada" };const sayHello = myBind(introduce, ada, "Hello");sayHello("!");
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
What this helper leaves out

This helper works like the built-in bind for normal calls: a fixed this plus saved arguments. It does not handle calls with new. It also doesn't set name and length the way the built-in one does. The later Polyfill call, apply & bind lesson builds a fuller version.

Where you'll use this

You'll meet these methods in four common places. The first is timers and event handlers. You hand them a function to run later. That function is called a callback. They often call your method without its object, so this is lost. bind keeps the right object. The later Losing this lesson covers this problem in depth. Here is a first look:

bind keeps the counter for a timerPop out in the code editor (opens in a new tab)JavaScript
const counter = {
  count: 0,
  increment() {
    this.count += 1;
    console.log(this.count);
  }
};

setTimeout(counter.increment.bind(counter), 1000);

setTimeout runs a function after a delay, here 1000 milliseconds (one second). Line 9 hands it a bound copy of increment. So this is still counter when it runs, and it prints 1.

The other three places:

  • Saving a first argument. const logError = console.error.bind(console, "Error:") makes a logger that always starts with "Error:".
  • Borrowing methods safely, especially hasOwnProperty.
  • Passing an array as separate arguments with apply. You'll see this in older code. Newer code uses spread.

Here is partial application with map. map calls a function once for each item in an array, and collects the results in a new array.

Save a label for map with bindPop out in the code editor (opens in a new tab)JavaScript
function labelTodo(prefix, todo) {
  return prefix + todo;
}

const labelDone = labelTodo.bind(null, "Done: ");
console.log(JSON.stringify(["email"].map(labelDone)));

Line 5 saves the first argument, "Done: ". Line 6 hands labelDone to map. map passes each todo as the next argument. It prints ["Done: email"].

call, apply, or bind?
  • Run introduce now with ada as this, and "Hi" and "!" listed one by one
  • Run Math.max now with numbers that are already in the array nums
  • Hand a method to a timer so it keeps its object
  • Make double from multiply by saving 2 as the first argument
  • Turn arguments into a real array with Array.prototype.slice
  • Pass all the arguments from one array called args
Try it yourself
0 of 6 correct

Put each task under the method that fits it best.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common misconceptions

  • "call changes the function forever." No. It picks this for one call that runs right away. The function stays the same.
  • "apply is an older bind." No. apply runs the function now and takes an array. bind runs nothing. It returns a new function for later.
  • "bind can only set this." No. It can also save the first arguments. That is partial application.
  • "You can change a bound function's this with call." No. A later call can add more arguments, but this stays the bound value.
  • "call can set this for an arrow function." No. An arrow function uses the this of the code around it, and call can't change that.
  • "apply and spread always do the same thing." Both pass an array's items one by one. But apply also accepts array-like objects, and spread does not.
  • "A borrowed method works on any value." No. It only works when the value has the properties the method reads.
  • "Our myBind is a complete polyfill." No. It shows the main idea: save the values, then pass them on to the real call. It leaves out new, name, and length.
Run now or run later?

Ask one question: does it run now? call and apply run the function now. bind makes a new function to run later.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict a call result
What does this program print?
Starter codePop out in the code editor (opens in a new tab)JavaScript
function introduce(greeting) {
  return greeting + ", " + this.name;
}
const ada = { name: "Ada" };
console.log(introduce.call(ada, "Hi"));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeBorrow join for a string
    Use method borrowing to make a-b-c from the string abc.
    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const result = Array.prototype.join.call("abc", "-");
    console.log(result);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFix a timer callback
      A timer calls a method later, without its object, so this is lost. Bind the method so it adds 1 to counter.count.
      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const counter = {
        count: 0,
        increment() {
          this.count += 1;
          console.log(this.count);
        }
      };
      const later = counter.increment.bind(counter);
      later();

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeMake a function with a saved first argument
        Make triple by saving the first argument of multiply with bind.
        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function multiply(a, b) {
          return a * b;
        }
        const triple = multiply.bind(null, 3);
        console.log(triple(4));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeWrite myBind
          Write the small helper from the lesson. Check that it gives the same result as the built-in bind for a normal call.
          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function myBind(fn, thisArg, ...preset) {
            return function boundFunction(...args) {
              return fn.apply(thisArg, [...preset, ...args]);
            };
          }
          function introduce(greeting, punctuation) {
            return greeting + ", I'm " + this.name + punctuation;
          }
          const ada = { name: "Ada" };
          const sayHello = myBind(introduce, ada, "Hello");
          console.log(sayHello("!"));

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            9 QUESTIONS
            call, apply & bind quiz · 9 questionsScore: first tries count
            1. Question 1 of 9Which method runs a function right away, sets this, and takes the other arguments one by one?

              Choose an answer to see the explanation.

            2. Question 2 of 9What does this code with call print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function show(punctuation) {
                console.log(this.name + punctuation);
              }
              show.call({ name: "Ada" }, "!");

              Choose an answer to see the explanation.

            3. Question 3 of 9What does this code with apply print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function add(a, b) {
                console.log(a + b);
              }
              add.apply(null, [2, 5]);

              Choose an answer to see the explanation.

            4. Question 4 of 9What does this code with an arrow function print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function makeGreeter() {
                const greet = () => this.name;
                return greet;
              }
              const greetAda = makeGreeter.call({ name: "Ada" });
              console.log(greetAda.call({ name: "Grace" }));

              Choose an answer to see the explanation.

            5. Question 5 of 9Spread is the newer way to pass an array's items. What does this code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const numbers = [4, 9, 2];
              console.log(Math.max(...numbers));

              Choose an answer to see the explanation.

            6. Question 6 of 9What does this code with a bound multiply print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function multiply(a, b) {
                console.log(a * b);
              }
              const double = multiply.bind(null, 2);
              double(6);

              Choose an answer to see the explanation.

            7. Question 7 of 9What does this code print when a bound function is run with call?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function show() {
                console.log(this.name);
              }
              const bound = show.bind({ name: "Ada" });
              bound.call({ name: "Grace" });

              Choose an answer to see the explanation.

            8. Question 8 of 9A user typed the key. Which older-style line safely checks whether obj has its own property with that name?

              Choose an answer to see the explanation.

            9. Question 9 of 9What does the small myBind in this lesson leave out on purpose?

              Choose an answer to see the explanation.

            Key takeaways

            • call(thisArg, a, b) runs the function now. You list the arguments one by one.
            • apply(thisArg, [a, b]) runs the function now. It takes the arguments from one array or array-like object.
            • bind(thisArg, a) runs nothing. It returns a new function that remembers this and any saved first arguments.
            • A later call can't change a bound function's this, and nothing can change an arrow function's this.
            • A borrowed method works when your value has the properties the method reads.
            • A small bind helper returns a function that runs fn.apply(thisArg, [...preset, ...args]). The built-in bind does a little more.

            Final definition: call, apply, and bind let you choose this. call and apply run the function now; bind makes a new function for later.

            Up next: Arrow functions & lexical this.

            CompleteFrontend Clear concepts. Working examples.