But
this
is preposterous!
Yes, it is.
this
?this
is a reference to some object. What does that mean? It means that this
is not something that has an intrinsic value.
Consider
let a=5;
a=5
in the above example tells us that a
has a value of 5
. Unlike a
, this
doesn’t have a value of its own. Instead, it is simply a reference to some other object in memory.
The best way to understand this
is to simply try a few things out. Open a node repl and simply type in this
and press enter. What do you get? You should get a screenful of strange things. These strange things are key value pairs, much like any other object. You might get something like this
Note: Colours might be different/absent based on your settings
The above screenshot represents what is called the global object. When you typed this
into your node repl, it referred to this global object which currently holds all the context. What context, you might ask?
Let us see.
Try this:
this.hero="goldie";
this.villain="silvery";
console.log(this.hero,"is greater than",this.villain);
produces
goldie is greater than silvery
Two things to note here.
this.hero="goldie"
, it didn’t complain about this
not being defined. Which means, this
was already defined.this
didn’t hold special meaning, you would think that this was just any other object.Now let us try this:
console.log(hero,"is greater than",villain);
produces
goldie is greater than silvery
What sorcery is this?! We defined this.hero
and this.villain
. How did hero
and villain
get defined. After all, we put attributes into some object called this
. How do hero
and villain
automatically get defined?
We need to understand that there is a global object that node uses. This global object is referenced by this
. Whenever we assign something to a variable, the variable gets defined within the global object.
Let us try it the other way around
sidekick="bronzy";
console.log(this.sidekick,"is also better than the villain");
produces
bronzy is also better than the villain
This means, that the association is both ways. When we define something on this
it becomes globally available and when we define something globally, it becomes an attribute in the global object.
The global object contains references to several things apart from variables that we define globally. We have all used console.log
. If you look at console.log
and didn’t know that console
was something special in Javascript, you would think that console
is an object.
In fact, console
is an object. Given that we never defined it, then it is likely that console
is defined in the global object. Let us see.
this.console
gives us
Console {
log: [Function: bound log],
info: [Function: bound log],
warn: [Function: bound warn],
error: [Function: bound warn],
dir: [Function: bound dir],
time: [Function: bound time],
timeEnd: [Function: bound timeEnd],
trace: [Function: bound trace],
assert: [Function: bound assert],
Console: [Function: Console] }
Further, when we do the following, see what happens:
this.console.log("Hello world");
produces
Hello World
Not only is there a reference named this.console.log
, but it works just like console.log
. It works that way because it is the same.
It is critical to note that this.something
and something
are only equivalent when this
is the global object. That means, node will not do a lookup of variables, functions etc unless this
is the global object.
var Person=function(name) {
this.name=name;
}
Person.prototype.jump=function() {
console.log(name,"is jumping");
}
Person.prototype.jumpTwice=function() {
jump();
jump();
}
let kavita=new Person("kavita");
kavita.jumpTwice();
results in
ReferenceError: jump is not defined
Why so? If you look at it, in the jumpTwice
method, there is a reference to jump
. The this
object when jumpTwice
is called is in fact the Person object and not the global object. Does javascript automatically know to call kavita.jump()
? The answer is that it does not. It only does a lookup on the global object. It doesn’t do lookup any other object. jump
will be called only if it is defined in the global context. But that won’t work, since we have a context. We don’t want the whole world to jump when jump is called. We want only Kavita to jump.
To make this work, we need to understand calling contexts.
To understand calling context, one must have read about why objects and constructors. So brush up on that if you haven’t already.
Let us briefly go back to our Square
example.
var Square=function(length) {
this.length=length;
}
Square.prototype = {
area:function() {
return this.length*this.length
}
}
var tile=new Square(10);
var areaOfTile=tile.area();
We all understand that when new Square
is called, then a new empty object is bound to the Square function and is then called. At this point, when this.length=length;
is executed, this
refers to the empty object.
Similarly, when tile.area()
is called, Javascript similarly changes this
to refer to the tile
object and then calls area
. So all references to this
in the area
method are simply references to what was placed before the area
function.
tile.area(); // Calling context in area is `tile`
chocolate.perimeter(); // Calling context in perimeter is `chocolate`
kavita.depositIntoAccount(200); // Calling context in depositIntoAccount is `kavita`
A calling context is simply the context that Javascript has called a function with. In the global context, this is the global object. In other cases, it is mostly the object to which that function belongs. Sometimes this is not the case as we will see later. But for the most part, as shown above the calling context is set to whoever/whatever made that call.
A picture is worth a thousand words, so here:
Note: The above image was generated using Python Tutor
As the image above illustrates, when we execute the code above, and when we eventually get to line number 7 that reads return this.length * this.length
, we can see that this
points to the same object that tile
points to. Note the blue arrow and gray arrow that lead from this
and tile
respectively.
I would highly recommend trying Python Tutor for yourself. It will definitely help you grasp these concepts better.