

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


======
DonHopkins
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
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
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.

------
MarkyPc3
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
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
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
Sorry, in JavaScript.

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

~~~
MarkyPc3
Sorry for assuming C++ or C#

