JavaScript provides this keyword that is very useful for web developers. It allows you to easily access variables and objects without explicitly defining them. But its meaning changes according to where it is used. If not used properly, this keyword may refer to a wrong object and give undesirable results. On the other hand, if you use it correctly, then it can simplify your programming a lot. Often web developers need to be able to access correct this inside callback function. In this article, we will learn how to do this.
What is this keyword
Before we proceed, it is essential to understand what this keyword is and how it works. In JavaScript, this is a reserved keyword used to refer to an object such as variable, function, etc. It is a read-only object and its value is set by the browser and cannot be changed by us. Its value changes according to where you use it. This too is done by web browser. For example, if you use it by itself or in a function, it refers to the global object such as window. If you use this in an object method, it refers to an object. If used in an event, it refers to the event receiver. Its scope is automatically determined by the web browser and can be changed using functions like call(), apply() and bind().
What is a Callback in JavaScript
We need to also understand how callback functions work to get this and callback to work together. Callback is simply a function that is passed as an argument to another function. It is generally called sometime or the other inside the outer function where it is passed as argument. The difference between the value of this object and any other variable is that the value of this depends on where it is called or run, whereas the value of variable depends on where it is defined. So, many developers assume that this will have the same value as it was in the callback where it was defined. But that is not always true. Let us learn this with an example.
function outer(callback){
inner();
}
function inner(){
console.log(this);
}
outer(callback);
Here is its output.
Window {0: Window, window: Window,
self: Window, document: document,
name: '', location: Location, …}
In the above example, we have defined callback function inner() that is called from inside function outer(). It prints the value of this global variable.
On the other hand, if you call the this variable inside a JS object, it behaves differently.
var obj={
name: "John",
a: function(){
console.log(this);
}
}
obj.a();
Here is the output.
{name: 'John', a: ƒ}
How to Access Correct This Inside Callback
There are several simple ways to access the correct this inside callback functions.
1. Using Arrow Function
JavaScript Arrow functions provide a shorter way to define functions and return values in JavaScript. Here is an example of how a regular JS function is written as arrow function.
// Regular Function
data = function_name() {
return "Hello World!";
}
//Arrow Function
data = () => {
return "Hello World!";
}
OR
data = () => "Hello World!";
It basically allows you to skip function name and return statement, since it always returns value by default. Let us say you have the following outer() function. Here we first set the value of this object’s data variable. Then we call inner object’s anonymous function as callback function. In this callback function, we display the value of this.data variable, assuming it to be what we assigned in the previous statement.
function outer(data, inner) {
this.data = data;
inner.on('data', function () {
console.log(this.data);
});
}
// Mock inner object
let inner = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
let obj = new outer('foo', inner);
In the above example, the callback function in inner object refers to Window. When we run this code, we get undefined as the output. The this.data called in inner.on() is different from what we have assigned in the previous statement. So, instead of using anonymous function, we can use arrow function to solve the problem with binding this variable.
function outer(data, inner) {
this.data = data;
inner.on('data', () => {
console.log(this.data);
});
}
This is because arrow functions do not have implicit binding of this variable. Therefore, when we refer to this.data it is looked up in global scope just as any other regular variable, and its value becomes available.
2. Using Another Variable
Another approach is to just use another variable to store this variable before callback scope. In this case, the browser will create a copy of this variable and store it in your new variable, which is free from implicit binding. The implicit binding occurs only on variables with name this. It is important to remember that such a variable is also available inside the callback. Here is an example where we have copied the this variable to that variable.
function outer(data, inner) {
this.data = data;
let that = this;
inner.on('data', function() {
alert(that.data);
});
}
3. Using Bind() function
Lastly, you can use functions like bind(), call() and apply() to point this keyword to another object inside callback function. As mentioned earlier, we cannot change the value of this keyword. What happens is that every function has its own bind() function that returns a new function with its own this property which is bound to a specific object. This new returned function will be a mirror of the original function where you have complete control over this property that it points to. Here is an example to illustrate it.
function outer(data, inner) {
this.data = data;
let bound = (function() {
alert(this.data);
}).bind(this); // bind called with the 'this' value of the outer function
inner.on('data', bound);
}
Conclusion
In this article, we have learnt several ways to access the correct this property inside callback functions in JavaScript. Callbacks and this property are both very tricky concepts in JavaScript and you need to carefully keep an eye on what this property is bound to, in order to get the right value. In case of confusion, just use console.log() to explicitly print the value of this property at different points of your code. This will tell you what this points to throughout your code. Thereafter, use any of the above methods for course correction, if this does not point to the expected value.
Ubiq makes it easy to visualize data, and monitor them in real-time dashboards. Try Ubiq for free.
Also read:
How to Return Response from Asynchronous Call in JavaScript
How Slicing in Python Works
How to Ask User Input in Python Until Valid Response
Sreeram Sreenivasan is the Founder of Ubiq. He has helped many Fortune 500 companies in the areas of BI & software development.