endJS

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.