top | item 7675959

Ask HN: How do you explain "this" to beginners?

3 points| bhaumik | 12 years ago | reply

9 comments

order
[+] DonHopkins|12 years ago|reply
In JavaScript, "this" is not a variable, or a binding in the local scope. It is a keyword, so it is magic. It was a terribly idiotic design decision, because the variable you'd want to close over most of the time is "this", but since it's not a variable, you can't close over it -- it's dynamically bound, in a really stupid way.

It's the cause of a lion's share of JavaScript bugs. No matter how well you know JavaScript, and how pedantically you understand how "this" works and why it's such a terrible design flaw, you will ALWAYS make mistakes with it, and you will ALWAYS have to go carefully over your code line by line looking for misuses of "this".

Whenever your JavaScript program is misbehaving, the first thing you should do is to search the relevant code for "this", and think carefully about how it might be bound. And even if your JavaScript program is not misbehaving in a way you can detect, you should still do that anyway, because it might just have some very subtle bugs caused by "this".

I've been writing code that starts out with "var self = this;" and then ONLY using "self" and NEVER using "this" except for the first line of a function that goes "var self = this;". That way there's a lot less chance of making mistakes, although it's still possible for that first "this" to be incorrectly bound -- you only want to do the "var self = this;" in top level functions, and all functions contained in them should use self and never use "this".

[+] brianchu|12 years ago|reply
It's whatever is to the left of the dot.

The exceptions:

1) when used with new, it's the new instance of the object (pretend that when you use the new keyword, an Object.create() call is inserted in the beginning of the constructor function),

2) when there's nothing to the left of the dot, it's the window object.

3) .call and .apply force this to be something else.

[+] DonHopkins|12 years ago|reply
UNLESS somebody calls your constructor as a function, instead of with "new".

It breaks my heart to see constructors that check to see if they were called as a function and then try to do the right thing by recursively calling themselves with "new".

There is no possible reason for calling a constructor as a function -- it is always the wrong thing to do, so it should be impossible, not tempting. Conflating functions with constructors was stupid. Why should there only be one possible constructor for a class, anyway?

And it's a terrible idea for constructors to try to silently correct mistakes that programmers make calling them in the wrong way, instead of asserting an error, because you know damn well those programmers are making that same mistake all over the place, and lots of other constructors don't try to correct the mistake of calling them directly as functions.

The idea of using functions as constructors, but requiring them to be called with "new", yet still allowing those functions to be called as normal functions, which seems like a very reasonable thing to do, especially if you're coming from Python, is the other incredibly idiotic JavaScript design flaw, up there with "this". It's like having a gaping wound that never heals and is just waiting for another infection to come along.

The other stupid thing about JavaScript is the idea that a subclass should inherit from an INSTANCE of its superclass, instead of from the superclass directly. Why insert one extra level of indirection and waste the time and memory and simplicity? And why require that the constructor of all classes that you might ever subclass be callable with no arguments to create a dummy intermediate instance through which a subclass can inherit its class? That puts restrictions on and adds needless complexity to how constructors work.

JavaScript was NOT a clearly thought out language, and it's insulting to Self to claim that Self was its inspiration, when there's no good way to dynamically change the prototypes an object inherits from at runtime, and an object can only inherit from one prototype. Self is SO SIMPLE and SO EASY to understand, yet JavaScript is so confusing, that comparing it to Self just sets you up to be surprised and disappointed if you know Self, or think badly of Self if you only know JavaScript.

And don't even get me started about JavaScript's and Brendan Eich's misconceptions about equality.

It's really a shame, because the fuzzy magical thinking that went into JavaScript made it a lot more complex and error prone that it would have been otherwise, if only it had been designed by somebody who knew what they were doing and learned from other language's mistakes without aping other language's mistakes, instead of having such a cargo cult design, and then having a cargo cult name slapped on to mislead people into thinking it had something to do with Java, which WAS written by somebody who knew what they were doing.

[+] lumpysnake|12 years ago|reply
Most of your explanation does not translate really well outside of javascript. Where did you get that the OP is using javascript?
[+] MarkyPc3|12 years ago|reply
If the beginner understands functions I tell them it's the specific object running the function call. If not, I tell them it's the object that owns the most immediate scope (as in the one "running the code"). Also important here is the definition of what an object is. The key sentence to memorize is: "An object is an instance of a class" which is to say that the two are not the same. Saying a class is a blueprint and an object is the actual house that was built according to the blueprint (the class definition)is a good way to get this through. "This" in the above analogy more easily means a reference to a specific house.
[+] DonHopkins|12 years ago|reply
Congratulations, you've set them up to get screwed every time they define a callback that uses "this" inside another function (which is an extremely common things to do in JavaScript). Any explanation of how "this" works that doesn't fully explain all the pitfalls of DYNAMIC BINDING of the KEYWORD "this" is just misleading and will teach people to write buggy code.

I'm not blaming you, it's not your fault, it's Brendan Eich's fault for such a crappy design. There is NO WAY to properly teach JavaScript without getting deep and dirty into the intricacies of how the virtual machine works and binds "this" dynamically at runtime.

You should explain why you should do "var self = this;" and use self instead of this inside of closures, because it's definitely going to bewilder new programmers when they see code in the real world that does that, and wonder why the fuck anyone would write something so crazy, and not realize that they should be writing crazy stuff like that themselves or else they will regret it.

It is very embarrassing to explain "this" after having extolled the virtues of lexical scoping and closures, having to explain that the variable you most often want to close over, "this", is not actually a variable, not lexically scoped the way it seems, but actually a magic keyword (as if that mattered to anyone learning the language).

The flaw is that "this" is dynamically bound in a way that 99% of programmers don't actually want it to be 99% of the time, and the bugs it causes are subtle and hard to spot, because you read the code as you meant it to behave, not as it actually does behave, so "this" looks just fine, but doesn't work the way it looks.

In the rare cases that you do actually want "this" to be dynamically bound instead of lexically scoped, there would have been many other ways to get that effect explicitly instead of implicitly.

The terrible way "this" works makes JavaScript code so much harder to understand and write and debug and prone to difficult to diagnose and spot bugs, so it's one of the first, most important things you should teach new programmers about the language, who should realize from day one that as cool and popular as it is, JavaScript is deeply flawed.

[+] kogir|12 years ago|reply
I'm pretty sure that the language in use matters here. Care to specify?

For example, the answers for JavaScript and C# are not the same.

[+] bhaumik|12 years ago|reply
Sorry, in JavaScript.

At Thinkful, we're experimenting with different methods & resources, but wanted some feedback from the more experienced developers here.