Understanding call(), apply() and bind() in JavaScript
CJ
Posted on January 1, 2021
In this tutorial, we will understand call, bind, and apply methods in JavaScript.
To understand these methods you should know "this" keyword in JavaScript, if you don't, read my article to understand about "this" keyword here:
Let's begin with why we need to know "this" keyword beforehand to understand call, bind, and apply methods
So now you must know that
- Every function gets
this
property automatically - The context of
this
is the function it is being called from, i.e., before the dot. For e.g.,
'use strict'
let userA = {
age: 9,
getAge() {
console.log(this.age)
}
}
// here context of getAge is object userA
userA.getAge() // 9
// or
let userB = {
age: 19
}
function getAge() {
console.log(this.age)
}
// here context of getAge is object userB
userB.getAge = getAge
userB.getAge() // 19
But sometimes we lose our reference this
An example:
'use strict'
let car = {
manufacturer: 'Mahindra',
model: 'XUV500',
featureArray: ['Sunroof', 'ABS', '4WD'],
carInfo() {
const info = `${this.manufacturer} ${this.model} have these features: `
const features = this.featureArray.reduce(function (string, feature, i) {
if (i === this.featureArray.length - 1) {
return `${string} and ${feature}.`
}
return `${string} ${feature},`
}, '')
console.log(info + features)
},
}
car.carInfo()
This will throw a TypeError: Cannot read property 'featureArray' of undefined
Which happens when code tries to access .featureArray
of this
which is on line 12
if (i === this.featureArray.length - 1) {}
According to error this.featureArray
is undefined.
Let's see why this happened:
'use strict'
let car = {
manufacturer: 'Mahindra',
model: 'XUV500',
featureArray: ['Sunroof', 'ABS', '4WD'],
carInfo() {
const info = `${this.manufacturer} ${this.model} have these features: `
// πhere this is referenced to car object
const features = this.featureArray.reduce(function (string, feature, i) {
console.log(this) // undefined
// πhere reference of this is unknown
if (i === this.featureArray.length - 1) {
return `${string} and ${feature}.`
}
return `${string} ${feature},`
}, '')
console.log(info + features)
},
}
car.carInfo()
The reference of this
is unknown because the anonymous function we pass to .reduce
does not get the context of user
.
Let's solve this problem with a hack first, by saving the reference of this
:
'use strict'
let car = {
manufacturer: 'Mahindra',
model: 'XUV500',
featureArray: ['Sunroof', 'ABS', '4WD'],
carInfo() {
const info = `${this.manufacturer} ${this.model} have these features: `
let savedReference = this
const features = this.featureArray.reduce(function (string, feature, i) {
if (i === savedReference.featureArray.length - 1) {
return `${string} and ${feature}.`
}
return `${string} ${feature},`
}, '')
console.log(info + features)
},
}
car.carInfo() // Mahindra XUV500 have these features: Sunroof, ABS, and 4WD.
We will fix this by using bind()
later in this article, before that
Let's learn about bind()
method available in JavaScript
The bind() method creates a new function that, when called, has
this
keyword set to the provided value.
'use strict'
let kid = {
Name: 'Rob',
Age: 6,
}
function sayHi() {
console.log('π Hello, I am ' + this.Name)
}
sayHi()
Here it will throw an error : TypeError: Cannot read property 'Name' of undefined
Because of sayHi() being called without any context, this
has not referenced to anything here.
So let's fixed the context of this
to sayHi() with bind()
'use strict'
let kid = {
Name: 'Rob',
Age: 6,
}
function sayHi() {
console.log('π Hello, I am ' + this.Name)
}
let logHi = sayHi.bind(kid) // creates new object and binds kid. 'this' of sayHi = kid now
logHi() // π Hello, I am Rob
So now we understand how bind
works, let's solve the car
problem with bind
instead of the previous hack above
'use strict'
let car = {
manufacturer: 'Mahindra',
model: 'XUV500',
featureArray: ['Sunroof', 'ABS', '4WD'],
carInfo() {
const info = `${this.manufacturer} ${this.model} have these features: `
const features = this.featureArray.reduce(
function (string, feature, i) {
if (i === this.featureArray.length - 1) {
return `${string} and ${feature}.`
}
return `${string} ${feature},`
// πhere we have bind the this object which is referenced to object car
}.bind(this),
''
)
console.log(info + features)
},
}
car.carInfo() //Mahindra XUV500 have these features: Sunroof, ABS, and 4WD.
Now we have covered bind()
, let's understand call()
and apply()
What is a call method in JavaScript?
Every function has a method
call
that allows invoking the function specifying the context (this
) and arguments the function will be invoked with
'use strict'
let kid = {
Name: 'Rob',
Age: 6,
}
function sayHi() {
console.log('π Hello, I am ' + this.Name)
}
sayHi.call(kid) // π Hello, I am Rob
We can pass arguments to it also :
'use strict'
let kid = {
Name: 'Rob',
Age: 6,
}
function sayHi(place, number) {
console.log(`π Hello, I am ${this.Name}, I live in ${place} and I have ${number} dogs`)
}
sayHi.call(kid, 'Montreal', 2) // π Hello, I am Rob, I live in Montreal and I have 2 dogs
Let's see how apply()
works :
call() and apply() are exact same thing. The only difference between how they work is that call() expects all arguments to be passed in individually, whereas apply() expects an array of all of our arguments.
'use strict'
let kid = {
Name: 'Rob',
Age: 6,
}
function sayHi(place, number) {
console.log(`π Hello, I am ${this.Name}, I live in ${place} and I have ${number} dogs`)
}
sayHi.apply(kid, ['Montreal', 2]) // π Hello, I am Rob, I live in Montreal and I have 2 dogs
I hope this article was helpful for you to understand call()
, bind()
, and apply()
.
Feel free to give a suggestion or shoot me a message on Twitter or LinkedIn and while you are at it checkout my Website.
See you in the next post!π
Posted on January 1, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
February 14, 2020