The easiest way to describe this
is that it refers to the object it's assigned when called. For example, consider this object:
const song = {
title: 'What is this thing called love',
writer: 'Cole Porter',
artist: 'Elsie Carlisle',
performed_by: function(){
return this.artist
}
}
When song.performed_by()
method is called, this
refers to song
. But before we actually execute the code, this
refers to nothing.
Consider the following two lines:
console.log(this.someVariableName)
console.log(someVariableName)
The first line outputs undefined
and the second throws an error, telling us that someVariableName
is undefined. If we define the variable without passing it a value, the output is the same in both cases
console.log(this.someVariableName)
let someVariableName;
console.log(someVariableName)
Which tells us that this
truly is waiting to be assigned to something.
Changing the context of this
A lot of people have sang the song over the years, let me tell you my current favorite versions:
let performers = [
{
artist: 'sant andreu jazz band',
listen_at: 'v=kZS2Kx1Hr9I'
},
{
artist: 'Rebecca Ferguson',
listen_at: 'v=O0FwMORV2Og'
}
]
When I run song.performed_by
I want one of the above artists to be returned! We do this by using call
, apply
or even bind
.
This is my favorite version of that song:
song.performed_by.call(performers[1])
//or
song.performed_by.apply(performers[1])
this
in performed_by
refers to another object, and so the output of the above code is Rebecca Ferguson
.
The difference between call
and apply
is how we pass arguments. In the above scenario there's no difference, but if we were to pass arguments, apply
passes them as an array.
Lets do another example
Let's change the code a little bit so that we return the title and the artist.
let song = {
...
performed_by: function(){
return `${this.title} by ${this.artist}`
}
}
let performers = [
{
artist: 'sant andreu jazz band',
listen_at: 'v=kZS2Kx1Hr9I'
},
{
artist: 'Rebecca Ferguson',
listen_at: 'v=O0FwMORV2Og'
}
]
Running song.performed_by()
will return the title and the song. But running song.performed_by.call(performers[0])
will return undefined by sant andreu jazz band
, that's because performers[0]
object doesn't have a title. Let's modify the code.
let song = {
...
performed_by: function(value){
let title = this.title ? this.title : value
return `${title} by ${this.artist}`
}
}
We can add the title as an argument
song.performed_by.call(performers[0], 'What is this thing called love')
If we use apply
the title would have to be passed as an array (and clearly, we'd have to reference it as title[0]
song.performed_by.call(performers[0], ['What is this thing called love'])
Using bind
bind
is similar to call
but used when we want to assign this
to an object without calling it
let announcement = function(title){
return `${title} by ${this.artist}`
}.bind(performers[0])
announcement('What is this thing called love')
In fact, the above snippet perfectly demonstrates the difference between call
and bind
let announcementFunction = function(title){ ... }.bind(performers[0])
let announcementValue = function(title){ ... }.call(performers[0])
Because of call
the anonymous function has executed and the value is attached to announcementValue
Useful places to use bind
might be on event listeners
document.querySelector('a').addEventListener('click', theMan.bind(song) )
Then we create theMan
which would take anything inside the song
object
const band = function(){
return `${this.artist} band`
}.bind(performers[0])
function theMan(e){
console.log(`${this.writer} wrote a great song
and the girls from ${band()} sing an amazing cover`)
}
When we click the anchor tag, we get the message Cole Porter wrote a great song and the girls from sant andreu jazz band sing an amazing cover
That's it, thanks for reading. Also, if you are anything like me when it comes to music, you'll like the youtube links I listed
Top comments (0)