DEV Community

YCM Jason
YCM Jason

Posted on

Is `this` in Javascript bad?

Recently I have an argument with a friend who absolutely hate the this keyword in Javascript. He claims that since the language has an ambiguous binding of this in different situations, e.g. const f = obj.g will lose the binding to obj, obj.g.call(obj2) will call g in the context of obj2..., the this keyword in Javascript is simply one of the worst thing in Javascript.

He also claims that Javascript would be a lot easier to code/maintain by avoiding the use of this keyword. He advocates the following pattern for object creation:

function Car() {
  const car = {};

  car.position = 0;

  car.move = () => car.position++;

  return car;
}

new Car();
// or
Car();
Enter fullscreen mode Exit fullscreen mode

I am, on the other hand, very comfortable with the this keyword. I use it a lot and appreciate how bind, call and apply works. However, I can't really find a legit argument against his pattern, because it really seem to be clearer for those who don't know much about Javascript?

What do you think? Give me some insights!

Top comments (39)

Collapse
 
ben profile image
Ben Halpern

¯_(ツ)_/¯

Collapse
 
jonasroessum profile image
Jonas Røssum • Edited

here, I think you dropped this: \ (pun intended)

Collapse
 
2ezpz2plzme profile image
Steven Liao • Edited

One thing about the pattern that your friend advocates is that it would be harder to use instanceof.

function Car() {
  const car = {};

  car.position = 0;

  car.move = () => car.position++;

  return car;
}

const car = new Car();

console.log(car instanceof Car); // false

You would have to do:

Object.setPrototypeOf(car, Car.prototype);

console.log(car instanceof Car); // true
Collapse
 
dmfay profile image
Dian Fay

It's sneaky. I've wasted a decent amount of time and effort due to forgetting that this isn't bound in fat-arrow functions, or having a different binding than I expect at whatever point in the code. I still like using this, but I'm not sure I could mount a bulletproof defense of it.

Collapse
 
nbageek profile image
Patrick Minton

I mostly agree with your friend, and I think ES6 has made it worse, because of how anonymous functions "break" the rules, which just confuses the hell out of junior devs:

foo: () => {
  // `this` isn't in `foo`'s context, it's in `foo`'s parent context.
}

I also kind of hate how everyone invents their own convention for re-assigning this to avoid context problems like so:

const that = this; // But some folks use `self`, or `_this`, or `this2`, etc.

const foo = function() {
  // do something with `that` here, since `this` is local to `foo`.
}

Having said that, it's use is extremely prevalent, so I wouldn't make a crusade of this. It's a lot being that guy who's always complaining that everyone uses the phrase "begging the question" wrong.

Collapse
 
nektro profile image
Meghan (she/her) • Edited

Arrow functions were made specifically so that the second example wouldn't have to happen anymore. Consider the following.

class Person {
    constructor(id) {
        console.log(this) // person
        const that = this;
        fetch(`https://api.acme.corp/people/${id}`)
        .then(x => x.json())
        .then(x => {
            console.log(this) // person
            Object.assign(this, x);
        })
        .then(function(x) {
            console.log(this) // window
            // `that` is the only reference to person in this scope
        });
    }
}
const person = new Person('12');

Ignoring how terrible that code is, arrow functions allow you to have functions in functions while still maintaining the scope of your parent, yes but this behavior was very much requested and intended

Collapse
 
nbageek profile image
Patrick Minton

I agree that this is a good thing....if you are senior enough at javascript to understand the nuances of the scope of this and you understand how arrow functions interact with this differently than "traditional" ones -- to many junior devs, () => is just shorthand for function(). The fact that it isn't is mostly the fault of this -- and is that extra "thing you need to know" really worth keeping this around?

I've always had a love/hate relationship with magic variables (back when I first encounterd $_ in perl my mind was a little blown).

I can completely understand how avoiding them makes for more readable code.

Thread Thread
 
nektro profile image
Meghan (she/her)

Using this in any language is a hallmark of doing anything in OOP. Yes, JS has some things to watch out for, but the idea anyone would consider trying to drop using this altogether instead of learning the time/place and make making great things so much easier escapes me.

Collapse
 
damcosset profile image
Damien Cosset

I think I agree with your friend. I don't hate the this keyword, I use it quite a lot myself. But I feel like the keyword this is prone to more errors than code trying to avoid it. Obviously, it all depends on the programmers writing the code.

To me, it seems safer to try to avoid using too much this. It also reads better I believe. When I'm reading code, I wouldn't want to ask myself every 2 lines: What is this this referring to?

Collapse
 
ycmjason profile image
YCM Jason

This I think really depend on the design of your system.

In angular/vue/react, the framework seem to have developed around the keyword this without an issue. I wonder why they have made this choice if this could be troublesome.

Collapse
 
damcosset profile image
Damien Cosset

I use React quite often. So, I use this a lot. I use arrow functions all the time, so every single this I use refers to the outer most instance, the component, every single time. Definitely a personal preference anyway :)

Thread Thread
 
ycmjason profile image
YCM Jason • Edited

the only advantage that I could think of using this is the ability of reusing functions. Using the method suggested by my friend will create a new function instance for every object created. But if we use class, essentially we are using prototype, so all the methods will only be defined once. It makes a difference when we are creating the same instance many many times.

Thread Thread
 
gmartigny profile image
Guillaume Martigny

It completely shatter the prototype which is bad IMO. Your friend's method not only create a new function each time, but prevent any ineritance.
Also, it's not possible to supercharge Car's prototype.

The "this" keyword can be tricky, but avoiding it leaves you in a land without OOP.

Collapse
 
eebbann profile image
Eban Emmanuel

that was. mostly for the class base component i suppose

Collapse
 
hrmny profile image
Leah

Yeah, but in react click handlers and other stuff most of the time need this, which leads to you either abusing class properties for arrow functions or having bind everywhere

Collapse
 
nektro profile image
Meghan (she/her)

While there are some historical gotcha's when using this in certain contexts, if you plan to use JavaScript in an OOP sort of way, I would in no way say that you should steer away from using this. On top of that, constructors should not be defined with functions anymore. They should be in a class where using new is forced and the meaning of this is unambiguous.

Secondly I would greatly avoid using .bind or .call as much as you can. Some of the easiest ways to lose track of this is using functions in this way..

Collapse
 
nichgalea profile image
Nicholas Galea

"since the language has an ambiguous binding of this in different situations"

Learn the situations, and use accordingly.

Refusing to learn how the tool you're using works will impede your work, or at minimum drastically reduces the quality of it.

I understand that JavaScript is "special" when compared to other languages, but working around it's eccentricities will only stop you from leveraging all that it has to offer.

Collapse
 
jesseditson profile image
Jesse Ditson

In javascript, there are no absolutes. Your friend is wrong if they believe a single pattern will always be correct. That being said, some guiding principles can be helpful:

  • this is valuable when you're working with a stateful object. You can ask yourself: is your object an instance of a "superclass", in that other instances of this object may exist and have different states? it's very likely that this is the right tool for the job. In fact, as of es6 the module pattern your friend uses should most likely be refactored to a class.

  • this could be considered dangerous when working with raw objects. If you find yourself using .bind a lot, or if you're calling this from inside a method of a non class-like object (e.g. you would never make more than one of the object/function), consider taking a more functional approach. With new Promises and arrow functions, functional javascript has become a lot more fun and readable.

This argument IMO is generally a hold-over from when javascript didn't have classes, so you had the option of either constructing using the module pattern like your friend, or using a function constructor and appending methods to the function's prototype. Nowadays, we don't have to argue because we have the class keyword.

Is this a minefield of possible mistakes in javascript? Absolutely not. It's part of the language, and gives us important OOP abilities. You should use it when appropriate!

Collapse
 
layflags profile image
Lay Flags

Have you seen Douglas Crockford's talk during Nordic.js 2014? There he said that he stopped using Object.create, new, this, etc. completely and instead uses the factory pattern for creating objects, similar to the pattern of your friend (around 25:00). After watching the video I tried it out and from then on I never missed these keywords. I rarely use the factory pattern nowadays, just if I really need it. Instead I try to code more functional

Collapse
 
jjwesterkamp profile image
Jeffrey Westerkamp • Edited

It is only when call, bind and apply are used for the wrong reasons - or excessively - that this starts to get unpredictable. In my opinion this is the exact thing that makes Javascript as powerful as it is.

this always points to the context of the call to the function within which the keyword is used.

Arrow functions do what they do because the above statement does not apply to them. Instead, they inherit their this value from their declaration context.

That's all there is to it. It is never arbitrary, nor should it be difficult to determine, where this points to. I think it's just a matter of awareness of the fact that you'll have to look for its value at the preceding call stack, instead of it's lexical scope.