What on Earth Is this
?
One thing that can be done to make a programming language terrible, is have some aspect of the syntax mean a different thing, in a potentially program breaking way, in subtly different contexts. JavaScript's this
keyword sets the gold standard for this exact problem.
In JS, this
refers to an object, but which object depends on the context. Here are some examples of where this
can refer to some confusing things.
In a function, this
will refer to a different thing depending on where the function is called, not where it is declared. For example, the this
keyword is supposed to refer to the global object when used alone, or in a function. If we for example declare a property of the global object and then reference it via this
in a function, we get the variable we declared:
variable = true;
let doSomething = function() {
console.log(this.variable)
};
doSomething()
So the above code outputs:
true
However when used on its own, at the top level, this
is also meant to refer to the same object, and yet the following code:
variable = true;
console.log(this.variable)
outputs:
undefined
Well that's confusing... This is not even mentioning the fact that putting the word let
or var
before variable
completely changes the meaning of the code, and thus you have to once again google the specific subtle semantics of slightly different ways of writing what should appear to be the same thing.
Now if we call this function on an object, despite being the exact same function defined in the same place, we get a different result. This is because now this
refers to that object. Hence the following code:
variable = true;
let doSomething = function() {
console.log(this.variable)
};
let obj = {
variable: false,
doSomething: doSomething,
};
obj.doSomething()
outputs:
false
Oh, and by the way, if you change the declaration of doSomething
to use an arrow function, the function no longer correctly references the global object or the object it is called on, and thus the following code outputs undefined
twice:
variable = true;
let doSomething = () => {
console.log(this.variable)
};
let obj = {
variable: false,
doSomething: doSomething,
};
obj.doSomething()
doSomething()
In one additional moment of stupidity though, functions such as call
can rebind the value of this
arbitrarily, meaning that in this block of code the final three lines also output three different values:
variable = true;
let doSomething = function() {
console.log(this.variable)
};
let obj1 = {
variable: false,
doSomething: doSomething,
};
let obj2 = {};
obj1.doSomething.call()
obj1.doSomething.call(obj1)
obj1.doSomething.call(obj2)
If this makes no sense at all, try reading the quite comprehensive Mozilla docs on how the this
keyword works. Not because it will make sense after reading them, but because you will realise that even after having it clearly explained, it still makes no sense.