JavaScript call(), apply() and bind() explained like you are five
Hello World, Akwaaba ๐. JavaScript newbies find it confusing to understand the difference between call()
, apply()
and bind()
methods and how the this
keyword fits in their world.
In a snapshot, these methods give you the ability to borrow a method of an object without creating a copy of that method.
In this post, I'll help you understand how to use call()
, apply()
, and bind()
to borrow another object's method.
Let's get started ๐
Brief intro to Properties, and Methods
A JavaScript object
can contain a function
, function
that are stored in object
properties are called methods
. Methods allow object
to act or do something.
When the method
is being defined in an object
, we may want to access some properties
or data
of the object
in the method's body to complete the task. We can also pass arguments
to the method
.
The code below shows a user
object with a greetings
method and a parameter
passed to the method. When the code is executed, it greets the user by name using the time of the day.
const user = {
firstName: "Emmanuel",
lastName: "Kumah",
greet: function greetings(timeOfDay){
console.log(`${timeOfDay} ${user.firstName} ${user.lastName}`)
}
}
In the greetings
method's body, because we want to access the user's firstName
and lastName
, we can do like below :
user.firstName
which gives access to the valueEmmanuel
user.lastName
which gives access to the valueKumah
A better option is to use the this
keyword in place of the user
object. So we can rewrite the code above like:
const user = {
firstName: "Emmanuel",
lastName: "Kumah",
greet: function greetings(timeOfDay){
console.log(`${timeOfDay} ${this.firstName} ${this.lastName}`)
}
}
What this
refers to
- The
this
keyword in the function's body always refers to theobject
it belongs to. It is theobject
calling the function - In the global context
this
will refer to thewindow
object orundefined
when in strict mode.
To execute the greetings
function, we call it like below:
/*Call greet method and pass in the argument "Good morning" */
user.greet("Good morning");
The output will be :
/*Good morning Emmanuel Kumah */
The
this
keyword in the function body will always point to theobject
calling thefunction
.So in our case, theobject
calling thefunction
will beuser
. As a result, wherever the keywordthis
is seen in the function's body it will point to theuser
object.In other words, the
this.firstName
will be evaluated asuser.firstName
which will give as the value :Emmanuel
, likewise ,this.lastName
will be evaluated asuser.lastName
which will give as the value:Kumah
.
Understanding what the this
keyword refers to in a function's body will be pivotal in understanding the call()
, apply()
and bind()
methods.
Understanding the call()
, apply()
and bind()
methods ?
To understand what, when, and how to use the call()
, apply()
and bind()
methods, let's take a look at the code sample below which allows you to book a train in the city of Accra, Ghana's capital
const eurostar = {
train: "Eurostar",
ticketCode : "Tr",
book(fullName, ticketID, departure){
console.log(`Hello ${fullName}, you have booked ${this.train} train,
your ticket id is ${this.ticketCode}${ticketID} and departs at ${departure}`)
}
}
/* Invoke the method and pass the needed arguments */
eurostar.book("Emmanuel Kumah", "ES001", "8:00 am")
The output will be :
/* Hello Emmanuel Kumah, you have booked Eurostar train,
your ticket id is TrES001 and departs at 8:00 am */
What is happening in the code above?
We defined a train object
eurostar
with the following properties,train
(name of the train station),ticketCode
and abook
method withfullName
,ticketID
anddeparture
parameters.What the
function
does is display the booking details to the user.To execute the function, we then call or invoke it like
eurostar.book()
We then pass the
arguments
to the parenthesis
To execute the function body, we invoke or call it and pass the needed data to the function's body like below:
eurostar.book("Emmanuel Kumah", "ES001", "8:00 am")
The output will be :
/* Hello Emmanuel Kumah, you have booked Eurostar train,
your ticket id is TrES001 and departs at 8:00 am */
Borrowing another object's method.
What if we decide to use the same book
method for another train station. What will happen ?
Because we want to write dry code, we decide to borrow the book
method in the eurostar
object and execute it on any object that want to make use of it.
So let's access the book
method in the eurostar
object and store it in the trainBooking
variable.
/* copy the book method and assign to variable */
const trainBooking= eurostar.book;
The trainBooking
variable is now a copy of the book
method. Now trainBooking
is also function.
To execute the code in the trainBooking
function, let's call
or invoke
the function.
Remember the function still has parameters so we need to pass arguments
to the trainBooking
function
Let's execute the function as below:
/* call the function and pass in the arguments */
trainBooking("Stephen Sam", "ES90","6:00pm");
The output will be:
/* Hello Stephen Sam, you have booked undefined train, your ticket id is undefinedES90 and departs at 6:00 pm */
Why are we getting undefined
when the code is executed ๐?
- When the
book
method / function is copied to thetrainBooking
variable, the variable now stores afunction
which still has thethis
keyword in the block of code.
To find outconsole.log(trainBooking)
.
In a regular function, the
this
keyword in the function's body will point to the globalwindow
object. However, thewindow
object does not have thetrain
andticketCode
properties.Now because we cannot access the
train
andticketCode
properties in thewindow
object, executing thethis.train
andthis.ticketCode
will have the valueundefined
. ๐ฒ
Does that mean we cannot borrow another object's method and execute the code in it ?
We can, let's see how to do that below ๐ช
How do we fix it ?
So how do we fix this
, how do we borrow another objects method and use it without encountering any errors. ?
- To fix it, we need to explicitly tell the
function
what thethis
keyword in it should refer to.
There are three function methods to use:
The
call()
methodThe
apply()
methodThe
bind()
method
Using the JavaScript call()
method for function borrowing
The
call()
allows for a function/method belonging to one object to be assigned and called for a different object.
What this means is, using the
call()
method, it is possible to invoke an object's method on a totally different objectWith
call()
, you can write a method once and then inherit it in another object, without having to rewrite the method for the new object
How to use the call()
method
The syntax for the call()
method is as below
functionName.call(thisArg, arg1, arg2, ...);
The
call()
method calls afunction
functionName with a giventhis
value andarguments
.The first argument of the
call()
method,thisArg
is the value ofthis
. Because thethis
value always refers to anobject
, we can simply write the object's name as the first argumentNow anytime the code is being executed and we come across,
this
keyword, it will refer to theobject
passed as the first argument.arg1
,arg2
... are the remaining arguments or data you want to pass to thefunction
Using the call()
method .
Now that you have understood, why we need the call()
method, let's now borrow the book
method defined in the eurostar
object and execute it on another train object.
Let's define a new train object fastTrack
which also have train
and ticketCode
properties , then borrow the book
method and use it on the fastTrack
train object.
The code below defines two objects: eurostar
and fastTrack
const eurostar = {
train: "Eurostar",
ticketCode : "Tr",
book(fullName, ticketID, departure){
console.log(`Hello ${fullName}, you have booked ${this.train} train,
your ticket id is ${this.ticketCode}${ticketID} and departs at ${departure}`)
}
}
/* object 2 */
const fastTrack = {
train: "fastTrack",
ticketCode: "Tr"
}
/* copy the book method from eurostar object and assign to the trainBooking variable */
const trainBooking= eurostar.book;
Let's use the call()
method to borrow the trainBooking
method of the eurostar
object on the fastTrack
object.
trainBooking.call(fastTrack, "Roberta Takyi", "FS032", "9:40pm")
The output will be :
/* Hello Roberta Takyi, you have booked fastTrack train, your ticket id is TrFS032 and departs at 9:40 pm */
Technically, the fastTrack
object has borrowed the book
method of the eurostar
object.
Why does the above work ๐ฒ?
Unlike the previous call, we are not getting any undefined
when we use the call()
method, because:
We explicitly set the first argument of the
call()
method to theobject
,fastTrack
Now, we pass the rest of the arguments,
Roberta Takyi
,FS032
and9:40 pm
to thetrainBooking
function
When an object uses a method of another object is called the function borrowing.
Using the
call()
method, we can now borrow a method and use it on anyobject
we define.
Another example of the call() method.
Now to conclude on the call()
method, let's define a greet
function that can greet any person depending on the time of day.
const person1 = {
firstName: "Emmanuel",
lastName: "Kumah"
}
const person2 = {
firstName: "Josephine",
lastName: "Tetteh"
}
/* Define the greet function */
function greet(timeOfDay){
console.log(`${timeOfDay} ${this.firstName} ${this.lastName}`)
}
/*use greet function on any of the person object using the call method*/
greet.call(person1, "Good morning")
/* Good morning Emmanuel Kumah */
greet.call(person2, "Good morning")
/* Good morning Josephine Tetteh */
With the above
- We called the
greet
function on theperson1
andperson2
objects. - The first argument of the
call()
method is theobject
thethis
keyword in the function body will refer to - The first argument will now be the
person1
andperson2
objects. As a result, anywhere we see thethis
keyword in the function body it will point to theobject
in the first argument. - The rest of the argument, will be any other data we want to pass to the function parameters.
Using the apply() method to borrow another object's method
Let's see how we can now use the apply()
method to do the same thing as above.
We take a look at the eurostar
train object created above , borrow the book
method and instead of using the call
method let's try with an apply()
method.
What is the apply() or Function.prototype.apply()?
The Function.prototype.apply() method allows you to call a
function
with a giventhis
value andarguments
provided as anarray
.
- The
apply()
method invokes thefunction
and allows you to pass inarguments
as anarray
.
Here is the syntax for the apply()
method :
functionName.apply(thisArg, [args])
The apply()
method accepts two arguments
The
thisArg
is theobject
which becomes the value of thethis
in the functionThe
args
argument is anarray
that specifies the arguments of the functionfunctionName
So if we wanted to use the apply()
method on the fastTrack
object, the code will be as below
const eurostar = {
train: "Eurostar",
ticketCode : "Tr",
book(fullName, ticketID, departure){
console.log(`Hello ${fullName}, you have booked ${this.train} train,
your ticket id is ${this.ticketCode}${ticketID} and departs at ${departure}`)
}
}
/* copy the book method and assign to a variable */
const trainBooking= eurostar.book;
const fastTrack = {
train: "fastTrack",
ticketCode: "Tr"
}
trainBooking.apply(fastTrack, ["Roberta Takyi", "FS032", "9:40pm"])
The output will be :
/* Hello Roberta Takyi, you have booked fastTrack train, your ticket id is TrFS032 and departs at 9:40 pm */
The function
book
accepts three parameters,fullName
,ticketID
anddeparture
The
this
value in the function's body will be set to thefastTrack
object.The
arguments
will be passed as anarray
,["Roberta Takyi", "FS032", "9:40pm"]
Difference between call()
and apply()
method.
The only difference of apply() with the call() method is that the second parameter of the apply()
method accepts the arguments to the actual function
as an array
.
- Instead of passing the
argument
to the function one by one, with theapply()
method, you pass theargument
as anarray
.
Using the bind() method to borrow a method
The
bind()
method returns a newfunction
, when invoked, has itsthis
sets to a specific value.
The this
keyword is set to whatever value we pass to bind()
.
The following illustrates the syntax of the bind()
method
fn.bind(thisArg[, arg1[, arg2[, ...]]])
Let now illustrate how to use the bind()
method.
/* Access the function */
const booking = eurostar.book;
/*Bind the booking function to the fastTrack object */
const bookFastTrack = booking.bind(fastTrack)
bookFastTrack("Ivy Donkor", "FS909", "7:00pm")
The output will be :
/* Hello Ivy Donkor, you have booked fastTrack train, your ticket id is TrFS909 and departs at 7:00 pm */
What is happening in the code above
We access the
book
function in theeurostar
object and store it in thebooking
variable.When we use the
bind()
method on thebooking
function, it is not invoked immediately instead, it returns a new function, with thethis
keyword in the function bound to thefastTrack
objectWe now store the returned function in a
bookFastTrack
variableFinally, we invoke the
bookFastTrack
function and we pass it the needargument
to get the expected output
So we are binding the booking
method to the fastTrack
object.
In Conclusion
In summary, the
call()
,apply()
andbind()
methods are mostly used to borrow a method from another object without making a copy of that method. This is known as function borrowing.You can use the
call()
orapply()
to invoke a function immediately.The
call()
will basically call a method on an object, with thethis
value set to theobject
. It helps you manually set theobject
The
bind()
method can be useful when a function needs to be called later in certain events
Did you find my article insightful, please help spread the word by sharing it on your social platforms? I would also love to read comments and feedback from you. Me daa se
PS: Akwaaba and Me daa se are Ghanaian ๐ฌ๐ญ dialect meaning, Welcome and Thank you respectively โค๏ธ