Home > Development, English, JavaScript, Programming > Don’t use this in JavaScript

Don’t use this in JavaScript

this JavaScript:

var o = {
    f1: function() {
        console.log('hi');
    },
    f2: function() {
        this.f1();
    }
};

o.f2.prototype.f1 = function() {
    console.log('bye');
}

var k = {
    f1: function() {
        console.log('pfff');
    }
}

new o.f2();
o.f2.apply(k);
o.f2();
var x = o.f2;
x();

There. That’s why I never use the this keyword in JavaScript.
And that’s why I think you should stop using it too.
Can you figure out what’s the output of this code?

If you run this piece of code on Chrome’s or Firebug’s console you will see something like (extracted form Firebug):

bye
pfff
hi
TypeError: this.f1 is not a function

The this keyword references a different object depending on how the function is called.
This could be a very powerful feature if it was not so misleading. When developers use this they expect it to reference one single object – thanks to many years of practicing using such keyword on languages like Java.

What happens there?

new o.f2();: When we call a function with the new keyword JavaScript will implicitly create an object and assign all this references in that function scope to that object, and return that object in the end. It will also create a reference to all of the properties of that function’s prototype in the newly created object.
When we do new o.f2(); we are doing exactly that, so when f2 gets executed it looks for a function called f1 (line 6) that belongs to that object. Since f2’s prototype gets assigned to the created object, that function would be the one that prints bye (line 10).

o.f2.apply(k);: All functions in JavaScript have a method called apply that will let you explicitly override the reference to this keyword during the execution of such function. That’s exactly what we are doing here. When f2 gets executed, this points to k, there fore pfff is logged, since k has a function called f1 that does that (line 14).

o.f2;: That’s the regular and usually expected behavior.

var x = o.f2; x();: We assign a reference to f2 to a variable called x. When we call x there’s no object associated with the call, so this points to nothing. When we try to access the property f1 in an undefined object, we get an error.

And if that’s not enough for you, here’s another example that shows another problem with this:

var object = {
  name: "simple object out here"
};

var anotherObject = {
  object: { name: "simple object in here" },
  p1: this.object.name,
  f1: function () {
    return this.object.name;
  }
};

console.log(anotherObject.p1);
console.log(anotherObject.f1());

This code outputs:

simple object out here
simple object in here

Maybe it’s just me, but I would logically expected it to output:

simple object in here
simple object in here

The thing is: using this in an object scope is not the same as using this in an object’s function scope.

So, please, don’t use this.
Or, use it as little as you can! When working with jQuery you will have to use this inevitably.
And that’s ok! But when writing your own, non-library-interacting code, minimizing the usage of this can make your code way simpler to understand and much less likely to have weird bugs – unless you really understand what all the different contexts this can refer to are. I know I get confused with the this keyword every now and then.

Happy JS-ing!

All the code shown in this post can be found here: https://github.com/luizfar/nothisjs

About these ads
  1. April 29, 2012 at 13:33

    Even though I do agree that “this” might be misleading, because it’s never a reference to an object per se, but rather it is a reference to the _context_ within which the function is being called, I think the key problem here is this: “When developers use this they expect it to reference one single object – thanks to many years of practicing using such keyword on languages like Java.”

    Don’t approach JS as if it is Java and you’re gonna be fine :) don’t try to come up with elaborate class models, with lots of inheritance, and in general don’t try to do OO in JS – it never turs out great for you.

    JS is mostly a functional language in the end (or it could be a great one if it wasn’t done by incompetent amateurs and now we have to live with it), so just try to approach it as such :)

    • May 1, 2012 at 07:51

      I do agree with you and I am sorry that I didn’t make it so clear in the post, besides the lines you quoted. But it’s exactly because there are so many non-JS developers out there writing JS code that I decided to write this post.

      I am fine with not approaching JS as Java for the browsers, but I can’t convince everyone, so I am at least trying to get them to write a bit more decent JS code, and then maybe, in slow steps, we can have more devs having a deeper understanding of the language.

    • May 4, 2012 at 17:49

      I’m sorry, Timur, but I disagree: Javascript is *not* mostly a functional language, even when written by experts. It is, by design, a prototype-based OO language. “this” is dangerous (and makes the language even less functional) because it makes the behavior of functions difficult to predict: any function which references it is not “pure” and thus difficult to reason about.

      The reason people struggle with OO in JS is because you can only stretch the jQuery idiom so far before it becomes difficult to organize code into logical units. JS code deals mostly with a big mutable object–the DOM–and so pure functional idioms are difficult to pull off. Classically this would have been handled with something like an MVC pattern, and although you can do pure-functional MVC by way of modules that’s not an idiom that most programmers, experienced JS hackers or otherwise, are used to dealing with (certainly most popular JS libraries aren’t written this way). So people reach for objects, and JS doesn’t have much to say about reasonable ways to structure and organize objects and reuse their code.

  2. April 29, 2012 at 18:49

    `this` IS confusing, that is true. I am currently teaching a course in javascript and delaying talking about the context parameter as long as possible. But don’t-use-it cannot be a blanket rule as it enables quite a bit of thing as well. A performance bonus and all sorts of other things when used correctly. Take jQuery Ui’s widget factory – how do you work with it other than by using ‘this’? You really can’t. The advice should really be don’t-use-this-unless -you-know-what-it-really-is.

    I’d be far more willing to entertain a don’t-use-new ban, though even there there are some very valuable scenarios (jQuery’s plugin system for example which again…would not work without ‘this’)

    • May 1, 2012 at 07:56

      Oh most definitely, if there’s one blanket rule I follow it is to never have blanket rules! And my post should definitely not be taken as one, I will in fact update it to make this more clear, thank you!

      When working with jQuery we will inevitably have to use the this keyword, and I think that’s completely fine. And I do agree with you on the don’t-use-new ban. If we look at the examples I’ve posted, most of them are not very common (I’ve rarely seen ‘call’ being used), so I think the most common one is definitely related to calling functions with the new keyword.

      But my main aim with this post is to demonstrate the perils of using this, more than trying to get people not to use it. I think I failed in making this clear on the post, thanks for pointing it out :)

  3. July 20, 2012 at 12:43

    Luiz, I’ve long felt the same way about this (and had the same frustration with jQuery); at one point I even drafted a blog post titled ‘This is this and That’s That’ before I came to my sheepish senses :-)

    What I’d like to point out here, for the two or three people who may not be aware, is that CoffeeScript makes dealing with ‘this’ much easier. Especially when dealing with objects (“classes”) and functions, there’s two possible values for the value of ‘this’ inside a member function, and the notation (‘->’ vs. ‘=>’) makes it crystal clear which you intend. (It’s up to you to remain sane with respect to that, of course.)

    As someone who’s dreaded JavaScript since oh, about the time Internet Exploder made it such a rapturous joy, I do appreciate CoffeeScript, jQuery and anything else that lets me put distance between my code and having to even be conscious of that Microsoft-branded miscreant.

  4. October 10, 2013 at 09:01

    javascript is a prototype-based OO language, but doesn’t mean you have to use inheritance in the traditional sense (parent and child classes). javascript is not good at modeling inheritance this way and I suggest not to. Two other ways to mimic inheritance is by composition or traits. Both have their disadvantages and advantages, but I recommend traits for javascript. Some argue that composition is better than true inheritance no matter what the language, because in true inheritance logic patterns arise (diamond problem), unmanageable parent-child relationships (pyramid anti-pattern), too much abstraction (causes yo-yo anti-pattern), and others. With respect to Traits, they haven’t hit the mainstream yet because the .NET languages don’t implement the frameworks. Point is, don’t pick a method that causes friction when developing with a specific language, but pick a method that lets you get the best out of the language. There’s always two ways to skin a cat. Peace out killahs!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: