We don't need this
There are a plethora of articles all over the web about what is this
in
JavaScript. That’s because this
is one of the most confusing topics about
JavaScript for juniors, even if they are experienced in other programming
languages.
There are many answers to the question “What is this
?” but from my point of
view, the answer is just one: “Technical debt,” and that’s because, for me,
anything written using this
, can and should be written without it.
Implicit isn’t good
this
is an implicit value, meaning we do not define it like arguments,
variables, etc. Instead, it is determined automatically for us. We might think
for a second, “that’s great,” but we have to consider that depending on where we
are in our code, this
changes, so we can’t be 100% certain about its current
value.
console.log(this); // Will log `globalThis`.
const object = {
shouldLogObject() {
console.log(this);
},
};
object.shouldLogObject(); // Will log `object`
[1, 2, 3].map(object.shouldLogObject); // Will log `globalThis` 3 times (???)
const aFunction = function () {
console.log(this);
};
aFunction(); // Will log `globalThis`
const arrowFunction = () => console.log(this); // Will log `globalThis`
aFunction.call("foo"); // Will log `"foo"`
Now, let’s see how this looks like if we don’t use this
:
console.log("hello"); // Will log `"hello"`.
const object = {
shouldLogArgument(argument) {
console.log(argument);
},
};
object.shouldLogArgument("foo"); // Will log `"foo"`
[1, 2, 3].map(object.shouldLogArgument); // Will log `1`, `2` and `3`
const aFunction = function (argument) {
console.log(argument);
};
aFunction("foo"); // Will log `"foo"`
// Will log the value of `argument`:
const arrowFunction = argument => console.log(argument);
aFunction("foo"); // Will log `"foo"`
It is almost the same amount of code, but now it is pretty clear what everything does because we are explicit about it.
The “solutions” are even worst
Some posts out there present “easy solutions” to this kind of issue using some
methods that come with a function: bind
, call
and apply
. To me, that’s
like putting patches over patches instead of fixing the root issue. For example,
let’s say that we have a function that takes a callback called onEvent
:
// with plain functions:
onEvent(doSomething); // readable, no issues here
// but with class methods:
onEvent(instance.doSomething); // will break if it uses `this`
// to "solve" that:
onEvent(event => instance.doSomething(event)); // verbose
// or
onEvent(instance.doSomething.bind(instance)); // wth?!
// or when we write the class itself:
class Example {
constructor() {
this.doSomething = this.doSomething.bind(this); // 🤮
}
}
If we don’t use classes
I already have a post about why we don’t need
classes to code, and this post is related, mainly because this
is extremely
common when working with class
. Some might even say that if we work with
static methods and stuff like that, then we don’t use this
, but my answer is:
Why are we even using class
then? We could have those static methods be
functions in a module and use them directly.
So is it useless to learn what this
is?
No, we need to know how this works, not to mention that there are many native
APIs in the browser and the server that uses classes, and learning how to deal
with this
is useful when working with them. However, we should avoid code that
uses this
to improve our lives and the lives of other developers.
Closing thoughts
I wrote this article mainly because some folks are explaining what this
is and
trying to “sell it” like something good when it’s something awful. So, everyone
should learn how to deal with this
if we encounter one in the wild, but avoid
it as much as possible in the code we write.