This is the article in a series about this keyword in JavaScript. If you haven't watched part one yet. Here is the link for your reference. This keyword in JavaScript - Part 1.
Continuing
with part two we go through other cases where we can use this keyword unlike
the original theory.
Table of
contents:
· Method .bind()
· Method .call()
Let’s go to
the contents!
Method .bind()
Let's start
with an example:
this.firstName = 'Global first name'
this.lastName = 'Global last name'
const user = {
firstName: 'User first name',
lastName: 'User last name',
getFullName: function () {
return `${this.firstName} ${this.lastName}`
}
}
const userObj = user.getFullName
console.log(userObj())
// => Global first name Global last name
console.log(user.getFullName())
// => User first name User last name
First, we have outside the global context we have this.firstName = 'Global first name' and this.lastName = 'Global last name'. This means that this keyword is referencing the Window object (Global context). Next, we have a user object that contains a method getFullName() and return this.firstName and this.lastName. In user this.firstName = 'User first name' and this.lastName = 'User last name'. We create a variable const userObject equals user.getFullName. That means the variable userObject is referring to the function getFullName, not the return value of the function. Finally, we console.log the two outputs and the two results are completely different. For the variable userObj the this keyword is referencing the Window object. When calling user.getFullName(), this keyword refers to the user object.
We can
conclude that this keyword when created will not refer to any object. Only when
we execute and call this keyword will the Javascript engine find and reference
the object for this keyword.
You see that
this keyword will be dependent on calls and dependencies and objects that call
this keyword. In case we
want this keyword to refer to exactly that object in any case, how should we
handle it? Let's see what .bind() in Javascript method can do to help you
realize this idea.
Let's go
back to the first example and use the .bind() method to see what's different:
this.firstName = 'Global first name'
this.lastName = 'Global last name'
const user = {
firstName: 'User first name',
lastName: 'User last name',
getFullName: function () {
return `${this.firstName} ${this.lastName}`
}
}
const userObj = user.getFullName.bind(user)
console.log(userObj())
// => User first name User last name
console.log(user.getFullName())
// => User first name User last name
Let's look
at the example above again. user.getFullName.bind(user) has been added. Note
that getFullName doesn't have "()". So how is the .bind() method?
The .bind()
method is pre-written in the prototype function in JavaScript. And all
functions when initialized will inherit this method. So how does the .bind()
method work?
First, when
you initialize const userObject = user.getFullName(user) then this keyword will
refer to user object and be assigned to userObject. A special thing is that the
.bind() method does not change this keyword in the user object, it creates a
new reference area, a new this keyword, and is completely referenced for the
user object. To understand value types and reference types, I have an article
you can refer to. Value types and reference types in JavaScript
This means
that when we use the .bind() method, we will return a new reference area. This
function will take the same arguments as the original method when using bind().
And the bind() method will receive n arguments. With this first argument being
the object that will be assigned this keyword. The following arguments are the
arguments that the original function took. Let's see the example to understand
better:
const user = {
age: 20,
getFullName: function (firstName, lastName) {
return `${firstName} ${lastName} - ${this.age}`
}
}
const userObj = user.getFullName.bind(user, 'Aka', 'Tak')
console.log(userObj())
// => Aka Tak - 20
const anotherUser = user.getFullName.bind(user, 'Hello', 'This keyword')
console.log(anotherUser())
// => Hello This keyword - 20
You can see
that when using the bind() method and adding arguments, we see that in any
case, it returns the same object assigned to the bind() method.
In another
case, you can still add arguments to the function initialized by the .bind()
method.
const user = {
age: 20,
getFullName: function (firstName, lastName) {
return `${firstName} ${lastName} - ${this.age}`
}
}
const userObj = user.getFullName.bind(user)
console.log(userObj('Aka', 'Tak'))
// => Aka Tak - 20
const anotherUser = user.getFullName.bind(user)
console.log(anotherUser('Hello', 'This keyword'))
// => Hello This keyword - 20
They still
give the same results. But when to add arguments and the .bind() method and
when to add a new function. For arguments that do not change over time we can
add the .bind() method. But for arguments that need to change often, we should
prefer the new function. Because the precedence of arguments is that arguments
in the .bind() method are always preferred. Let's see an example:
const user = {
age: 20,
getFullName: function (firstName, lastName) {
return `${firstName} ${lastName} - ${this.age}`
}
}
const userObj = user.getFullName.bind(user, 'Hello', 'This keyword')
console.log(userObj('Aka', 'Tak'))
// => Hello This keyword - 20
So we know
how to use the .bind() method and how to pass arguments. And the precedence of
the arguments. Let's see how the application in real life will be?
const body = document.querySelector('body')
const div = document.querySelectorAll('div')
const anchor = document.querySelector('a')
const img = document.querySelector('img')
const span = document.querySelectorAll('span')
When you're
working with the DOM, this is the usual way to get elements (elements). The
querySelector syntax is repeated many times. So we will apply the .bind()
method to shorten the syntax.
const $ = document.querySelector.bind(document)
const $$ = document.querySelectorAll.bind(document)
const body = $('body')
const div = $$('div')
const anchor = $('a')
const img = $('img')
const span = $$('span')
The
document.querySelector (document.querySelectorAll) method first calls the
.bind() method and passes document. This means that this keyword in method querySelector()
(querySelectorAll()) is referenced for document. And finally you assign this
block to $($$). Instead of using duplicate over and over again. Now you can use
$ for document.querySelector and $$ for document.querySelectorAll.
Method
.call()
Similar to
the .bind() method, we have a .call() method that is also written in the
function's prototype. And functions when created will inherit this method. So
let's see an example to learn how the .call() method works:
const user = {
firstName: 'User first name',
lastName: 'User last name',
getFullName: function (age) {
console.log(`${this.firstName} ${this.lastName} - ${age}`)
}
}
const user1 = user.getFullName.call(user, 20)
// => User first name User last name - 20
You can see
that the syntax of the .call() method is exactly the same as the .bind()
method. Also taking in the first argument is the object to be assigned with
this keyword. The following arguments will be the function's input parameters.
And the created user1 object is a new object, the new this keyword. The .call()
method is included with the .bind() method and executes immediately. Although,
the getFullName() method has not been called to execute. But you can see the
result printed right after we call method.call(). This is one of the features
of method.call().
Note that
if you do not have a specific purpose, you should not use the .call() method,
but use the normal run function.
Another case
where we can use the .call() method is to ensure inheritability. Let's look at
the example:
function Animal(name, age, legs, weight) {
this.name = name
this.age = age
this.legs = legs
this.weight = weight
}
function Dog(name, age, legs, weight, berk) {
Animal.call(this, name, age, legs, weight)
this.berk = 'Ow! Ow!'
}
function Cat(name, age, legs, weight, food) {
Animal.call(this, name, age, legs, weight)
this.food = 'Rice'
}
const chihuahua = new Dog('Chihuahua', 1, 4, '10 pounds')
console.log(chihuahua)
// => Object { name: "Chihuahua", age: 1, legs: 4,
// weight: "10 pounds", berk: "Ow! Ow!" }
const kitty = new Cat('Kitty', 0.4, 4, '5 pounds')
console.log(kitty)
// => Object { name: "Kitty", age: 0.4, legs: 4,
// weight: "5 pounds", food: "Rice" }
You can
reuse the parent function Animal. Children function can be reused and passed
.call() method.
Conclusion
In the first
part we learned how this keyword works. Coming to part two we will use this
keyword according to our wishes. Specifically through the .bind() and .call()
methods.
If you have
any ideas, feel free to comments below. Thank you for joining with me. Have a
good day!
0 Nhận xét