In JavaScript, the this
object can mean different things in different contexts. It mostly depends on the location where the this
keyword is located. If it’s in an object, then this
is the object. If this
is in a function, then this
is the function. For classes, this
would be the class since it’s just syntactic sugar for normal constructor functions. In JavaScript functions, there’s a call
, bind
, and apply
methods to change the value of this
inside a function. In this article, we’ll look at them closely and how to use them to change the value of this
. These methods only apply to regular functions and not arrow functions.
call
The call
method lets us call a function with the given this
object that we pass into the argument when we call it and arguments for the function provided individually.
It takes multiple arguments. The first argument is an object that we want to set to be the value of this
inside the function that we’re calling the call
method on. It’s an optional argument. We can set it to an object, null
or undefined
. In non-strict mode, null
and undefined
will be replaced with the global object and primitive values will be converted to objects. The second and subsequent arguments are arguments that we pass into the function.
The return value of the call
method is the same function it’s called on with the specified this
value and arguments.
The purpose of the call method is that we can reuse the same function with a different this
value without writing a new value with the this
value that we want.
For example, we can change the value of this
in a function with the call
method by writing the following code:
let obj = {
firstName: 'Joe',
lastName: 'Smith'
}
let person = {
firstName: 'Jane',
lastName: 'Smith',
getFullName() {
return `${this.firstName} ${this.lastName}`
}
}
console.log(person.getFullName());
console.log(person.getFullName.call(obj));
In the code above, when we call person.getFullName()
we get ‘Jane Smith’ since we have firstName
set to 'Jane'
in the person
object and lastName
set to 'Smith'
in the same object. Since this
is the person
object inside the getFullName
function, we get back ‘Jane Smith’ as a result.
When we use the call
method to change the this
object inside the getFullName
function to obj
by calling person.getFullName.call(obj))
, we get ‘Joe Smith’, since we changed this
to obj
which has firstName
set to 'Joe'
and lastName
set to ‘Smith’
.
We can also use the call
method for constructor functions. For example, if we have:
const Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}const Employee = function(firstName, lastName, employeeCode) {
this.employeeCode = employeeCode;
Person.call(this, firstName, lastName)
}
const employee = new Employee('Jane', 'Smith', '123');
console.log(`${employee.firstName} ${employee.lastName}`, employee.employeeCode);
Then in the Employee
constructor, we call the Person
constructor function that we previously defined. When we create a new Employee
object, we pass in a new firstName
and lastName
, and then inside the Employee
constructor, we used the call
method of the Person
function to pass the firstName
and lastName
to the Person
constructor, thereby setting the value for the firstName
and lastName
properties of this
without setting them in the Employee
constructor directly.
When we run console.log
on the last line, we get 'Jane Smith'
and '123'
.
Another example is that we can use call
with anonymous functions. For example, we can write the following function to log a greeting:
(function(greeting) {
console.log(`${greeting} ${this.firstName} ${this.lastName}`);
}.call({
firstName: 'Joe',
lastName: 'Smith'
}, 'Hello'));
In the function call above, we pass in an object with the firstName
and lastName
properties to the first argument of the call
method of the anonymous function. Then we pass in the string 'Hello'
in the second argument, which is passed into the first parameter of the anonymous function. This means that 'Hello'
is the value of the greeting
parameter, and this.firstName
is 'Joe'
and this.lastName
is 'Smith'
.
So, we should get 'Hello Joe Smith’
when we run the code above.
apply
The apply
method is almost the same as the call
method, except that we pass in an array for the second argument as the arguments for the function call instead of a comma-separated list of objects.
This means we can replace call
with apply
in the examples above by making some small changes.
The first example would be the same except that we change call
to apply
since we didn’t pass in the second or subsequent arguments:
let obj = {
firstName: 'Joe',
lastName: 'Smith'
}
let person = {
firstName: 'Jane',
lastName: 'Smith',
getFullName() {
return `${this.firstName} ${this.lastName}`
}
}
console.log(person.getFullName());
console.log(person.getFullName.apply(obj));
If we chain constructors with the apply
method for constructor functions, then we have to change call
to apply
and change the arguments list into an array. For example, if we have:
const Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const Employee = function(firstName, lastName, employeeCode) {
this.employeeCode = employeeCode;
Person.call(this, firstName, lastName)
}
const employee = new Employee('Jane', 'Smith', '123');
console.log(`${employee.firstName} ${employee.lastName}`, employee.employeeCode);
like we did above, then we just have to change it to:
const Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const Employee = function(firstName, lastName, employeeCode) {
this.employeeCode = employeeCode;
Person.apply(this, [firstName, lastName])
}
const employee = new Employee('Jane', 'Smith', '123');
console.log(`${employee.firstName} ${employee.lastName}`, employee.employeeCode);
Then we get the same output as we did above.
Finally, for the last example, we can change the code from:
(function(greeting) {
console.log(`${greeting} ${this.firstName} ${this.lastName}`);
}.call({
firstName: 'Joe',
lastName: 'Smith'
}, 'Hello'));
to:
(function(greeting) {
console.log(`${greeting} ${this.firstName} ${this.lastName}`);
}.apply({
firstName: 'Joe',
lastName: 'Smith'
}, ['Hello']));
Then we get the same output as we did before the change.
bind
The bind
method is only for changing the value of this
in a function. Like call
and apply
, it can be used to send arguments into the function.
It takes multiple arguments. The first argument is an object that we want to set to be the value of this
inside the function that we’re calling the bind
method on. This argument is ignored if the bound function is constructed with the new
operator. When we use the bind
method to create a function that’s supplied as a callback inside the setTimeout
function, then any primitive value passed into the first argument is converted to an object. If not arguments are provided to bind
, the this
value of the executing scope is treated as the value for the new function.
The second and subsequent arguments are arguments to prepend to the list of arguments when we call the function with bind
.
The return value of the bind
method is the same function it’s called on with the specified this
value and arguments.
For example, if we call bind
with no argument like in the following code:
let person = {
firstName: 'Jane',
lastName: 'Smith',
getName(){
return `${this.firstName} ${this.lastName}`
}
}console.log(person.getName.bind()());
Then we get undefined undefined
because this
would be set to the window
object since the this
of the executing scope is a window
object since it’s run at the top level.
If we call bind
with an object passed in, like in the following code:
let person = {
firstName: 'Jane',
lastName: 'Smith',
getName() {
return `${this.firstName} ${this.lastName}`
}
}
const joe = {
firstName: 'Joe',
lastName: 'Smith'
}
console.log(person.getName.bind(joe)());
We get 'Joe Smith'
since we passed in the joe
object into the first argument of the bind
method, which sets the this
object inside the getName
method to the joe
object.
Also, we can get pass arguments into a function with bind
. For example, we can add a greet
method that takes a greeting
and an age
parameter and return a new string with all of them combined together with the existing fields as we have in the following code:
let person = {
firstName: 'Jane',
lastName: 'Smith',
getName() {
return `${this.firstName} ${this.lastName}`
},
greet(greeting, age) {
return `${greeting} ${this.firstName} ${this.lastName}. You're ${age} years old`
}
}
const joe = {
firstName: 'Joe',
lastName: 'Smith'
}
console.log(person.greet.bind(joe, 'Hello', 20)());
If we run the code above, then we get 'Hello Joe Smith. You’re 20 years old’
since we set this
to joe
by passing joe
into the first argument of the bind
method. Then we pass in our arguments to the person.greet
method by passing in 'Hello'
, and 20 as the second and third arguments of the bind
method, which gets passed into the first and second argument of the greet
method call.
We can also use it with the setTimeout
function. According to the definition of bind
that we have above, if we pass in a primitive value to the first argument of bind
of the callback function for the setTimeout
function, then it’ll be converted to an object. For example, if we have:
setTimeout(function(x, y) {
console.log(this, x, y);
}.bind(1, 1, 1), 1)
Then we get Number {1} 1 1
from the console.log
output in the callback function since we have the primitive value one in the first argument converted to an object, then the other 2 arguments are the arguments that are passed into the callback function when it’s called.
In JavaScript functions, there’s a call
, bind
, and apply
methods to change the value of this
inside a function. In this article, we’ll look at them closely and how to use them to change the value of this
. They only apply to regular functions since arrow functions don’t change the value of this
. All 3 are very similar in that they all change the value of this
and let us pass in arguments to the function that they’re called on.