I know that this
subject could be confusing for even experienced developers but I want to explain it using my knowledge and experience and using my own words.
I will use word invocation and function calling interchangeable.
What is this?
I understand this as a context(object) for function in which this function is executed. Kyle Simpson in his book "You don't know JS" explains this
more deeply, so if you want to know everything about this
you should check his book. It's free available in github.
For this post what you should know is:
Execute function without any bind, call, apply method and without any object explicitly (like x.a()) always -> this always refers to global:
a();
No matter where you see this type of function call, this always refers to global object.
This in callback
function get(url, success) {
let httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url);
httpRequest.onload = success;
httpRequest.send();
};
function successHandler() {
console.log(this);
}
const apiKey = 'd126cacbbfebf7c84ad878e9deffc0e1';
const url = 'https://api.openweathermap.org/data/2.5/weather?q=los+angeles&APPID=' + apiKey;
get(url, successHandler);
What is the output of console log?
XMLHttpRequest object
Why?
Because we assigned a whole function definition (imagine function definition as a chocolate box) to onload property in XMLHttpRequest object, so now our function is a method. When the data get back from request our method is executed and because the owner (object, context) of the methods is a XMLHttpRequest object this
is binding to this object.
We know that our function is executed like this:
XMLHttpRequest.onload()
So we explicitly show the owner of the function (XMLHttpRequest object) and implicitly bind this
to this object.
But what if we want to pass arguments to our function?
If we do something like that:
function get(url, success) {
let httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url);
httpRequest.onload = success(httpRequest.responseText);
httpRequest.send();
};
function successHandler(data) {
console.log(this);
console.log(data);
}
const apiKey = 'd126cacbbfebf7c84ad878e9deffc0e1';
const url = 'https://api.openweathermap.org/data/2.5/weather?q=los+angeles&APPID=' + apiKey;
get(url, successHandler);
We try to invoke
XMLHttpRequest.onload()
but now it is not a method call but call on outcome of the success(httpRequest.responseText)
invocation with some unexpected result. We try to use parenthesis to call a method but except we have not calling a method but the outcome of success(httpRequest.responseText)
invocation. This is similar behavior to do this:
let a;
a();
You have type error because you cannot invoke a variable.
So what we should do?
function get(url, success) {
let httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url);
httpRequest.onload = function() {
success(httpRequest.responseText);
}
httpRequest.send();
};
function successHandler(data) {
console.log(this);
console.log(data);
}
const apiKey = 'd126cacbbfebf7c84ad878e9deffc0e1';
const url = 'https://api.openweathermap.org/data/2.5/weather?q=los+angeles&APPID=' + apiKey;
get(url, successHandler);
Now we have onload as a method. When onload is invoked our success handler is invoked similar to:
a();
So its this context is global.
How to create this context to XMLHttpRequest:
We can use bind to set this and argument and immediately invoke.
function get(url, success) {
let httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url);
httpRequest.onload = function() {
success.bind(this, httpRequest.responseText)();
}
httpRequest.send();
};
function successHandler(data) {
console.log(this); //XMLHttpRequest
console.log(data);
}
We can simply create new function and bind success function to this and assign to newly created variable
function get(url, success) {
let httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url);
httpRequest.onload = function() {
let bindedSuccess = success.bind(this);
bindedSuccess(httpRequest.responseText);
}
httpRequest.send();
};
function successHandler(data) {
console.log(this); //XMLHttpRequest
console.log(data);
}
Use arrow function
function get(url) {
let httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url);
httpRequest.onload = function() {
((data) => {console.log(this)
console.log(data);})(httpRequest.responseText);
};
httpRequest.send();
};
const apiKey = 'd126cacbbfebf7c84ad878e9deffc0e1';
const url = 'https://api.openweathermap.org/data/2.5/weather?q=los+angeles&APPID=' + apiKey;
get(url);
Top comments (0)