
JavaScript: Clarifying The Keyword ‘this’ - henryzhu
http://henrycode.tumblr.com/post/37627169791/javascript-clarifying-the-keyword-this
======
drblast
JavaScript has a number of nice features that do make sense, and if you
understand how prototype chains work and such the complexity is worthwhile.
"This" hasn't been one of those features for me.

I'm sure "this" makes sense in some context, but it forces me to think about
the implementation of the language way too much without any benefit that I
consider it a misfeature. So I don't use it.

Instead, I capture it with another variable in a prototype declaration:

    
    
       var that = this;
    

and refer to "that" everywhere in the prototype. Tends to be a lot simpler,
and usually for event handlers I'll create a closure to avoid the issue
entirely.

------
josteink
The fact that people are still writing clarifications for what something
seemingly as simple as "this" actually _means_ is just another argument for
avoiding it entirely.

It's a huge source of sneaky, little errors and you wont find any JS object
I've written without the first line being "var self = this;".

Basically "this" considered harmful.

------
jpolitz
The this keyword is confusing, it's good to see posts clarifying it. However,
while the rule in the post will be right in many cases, this list is
incomplete, even for some common usages of this, and might lull folks into a
false sense of security:

1\. "To the left of the dot" should be "to the left of the dot or bracket".
E.g. o["foo"]() also passes o as this.

2\. When you pass callbacks to built-ins like forEach, you can supply a
thisArg, and if you don't, this will be bound to undefined
(<http://es5.github.com/#x15.4.4.18>). (EDIT): Copying from cwmma below. Some
callbacks, like setInterval and setTimeout, pass the global object rather than
undefined. I suspect that DOM callbacks tend to use the global object and JS
callbacks tend to use undefined, but that's not a blanket statement by any
means.

3\. This isn't purely JS, but when interacting with the DOM, this is also
implicitly bound as a DOM element in event listeners. E.g.
document.addEventListener('click', function() { console.log(this); }) will
print the document object when you click on the page. This is quite relevant
for any JS web development; if it makes it easier to conceptualize, imagine
that the browser is calling a method with the DOM element to the left of the
dot.

4\. When the caller is strict mode code and the function is called without
method-call syntax, undefined is passed as the this argument rather than the
global object. You should always use strict mode to avoid accidentally handing
the global object around (in strict mode, the "set to global" option is
skipped in <http://es5.github.com/#x10.4.3>).

5\. When using this at the toplevel (which is allowed), it is bound to the
global object even in strict mode (<http://es5.github.com/#x10.4.1.1>).

And a few more esoteric ones:

6\. In addition to call and apply, Function.prototype.bind() can also change
the this parameter of a function, and violate the "left of the dot or bracket"
rule (<http://es5.github.com/#x15.3.4.5>, see boundThis).

7\. Inside a with() {} block (which you should never use, but we're trying to
cover our bases here), this is bound to the object passed to with in the
parentheses.

8\. If a property is a getter or a setter, this is bound to the object to the
left of the dot or bracket in the field access or assignment expression. This
actually matches the rule in the post except for the fact that the "call time"
is implicit; there are no () in the expression o.x, but it may call a getter
function for x that passes o as this (<http://es5.github.com/#x8.12.3>).

(EDIT): One more doozy:

9\. The dot and bracket operators implicitly convert primitives like numbers,
strings, and booleans to objects, so it's not exactly what's to the left of
the dot:

    
    
        Number.prototype.identity = function() { return this; }
        var x = 5
        var x2 = x.identity()
        typeof x2 === 'object' (true!)
        typeof x2 === 'number' (false!)
    

You can get the raw primitive if you make the function strict:

    
    
        Number.prototype.identity2 = function() { "use strict"; return this; }
        var x = 5;
        var maybe_five = x.identity2();
        typeof maybe_five === 'object' (false)
        typeof maybe_five === 'number' (true)
    
    

Please correct me if I've forgotten any...

~~~
abecedarius
Do any of you just avoid 'this' and write your Javascript like infix Scheme?
You can define objects via JSON literals with function values, and the result
seems both simpler to think about and more pleasant to read. (JS engines are
tuned for thissy code instead, I think unfortunately, but you can fall back to
using prototypes where it makes a difference.)

~~~
gruseom
Yes indeed. I don't bother with 'this' at all, except when forced to by some
interface. I don't even bother to define objects most of the time, just top
level functions that can easily be called from a REPL. That simple subset of
JS is powerful enough to go a long way — long enough that I'm unconvinced one
needs anything else, unless one believes one does — and programming this way
feels liberating, like riding a bicycle instead of pushing a car.

~~~
lopatin
Are you able to write large applications like this without things getting too
messy? I'm interested because I usually write JavaScript in the complete
opposite way than you just described (strictly OOP, almost like I'm writing
Java). This also means that I use 'this' quite a lot. Do you come from a
functional programming background? What do you think about languages like
clojurescript?

~~~
gruseom
My main work is on a complex application, but we write it in Parenscript, a
Lisp that compiles to Javascript (so yes, I do like languages like
Clojurescript). That gives us escape hatches for controlling complexity that
raw Javascript doesn't have. On the other hand, I do still write some raw
Javascript and I prefer the same style in both. As far as I can tell from
various measurements, the Lisp I write is about half the size of what I would
write in JS. That's a win, but not so big that it can be the only strategy for
limiting complexity.

Do I come from a functional programming background? Not really. I use closures
and lambdas a lot, but my code is rather imperative. My obsession when
building systems is to keep the code as simple and small as I reasonably can.
Mutable state and even global state don't scare me as long as they help with
that. What scares me are architectural assumptions about how one "should"
structure complex software.

This sort of thing is a bazillion times more fun to discuss in person, whilst
drinking beer, than it is in the contactless format in which we find
ourselves. I'd try to convince you that you might do well to drop your OO
assumptions, but I'm afraid of coming across as shrill. There isn't enough
context here to make one's claims nuancedly enough, and then also "nuancedly"
is not a word.

------
mistercow
The ability to wrangle `this` via fat arrows is one of the nicest things about
CoffeeScript.

------
ryanjodonnell
Please fix the indentation in the image. I was so confused by it until I
noticed that "location" and "locate" are both properties of the person object.
They should both be indented the same.

------
ender7
Sadly, one last, unfortunate inconsistency:

All event handlers have the value of 'this' bound to the object that emitted
the event:

    
    
      var div = document.createElement('div');
      div.addEventListener('click', function(e) {
        console.log(this); // prints <div></div>
      });

~~~
flebron
That's not a JS inconsistency, that's just the browser calling
yourhandler.call(yourobject, eventobject).

The underlying statement is that "event handler" is not a concept in JS, it's
just a way of calling functions that some implementations use for some things
(browsers for actions, node for I/O, etc...).

In fact, this didn't use to be true of old IE versions if I remember
correctly, so it's not a matter of the language, but of what the browser does
with your function during event firings.

~~~
ender7
You can get the current emitting object via e.currentTarget. Modifying 'this',
while cute, just makes yet another thing that must be explained to people when
you start talking about 'this'.

------
jrajav
You could probably factor exceptions 1) and 3) into the rule too!

    
    
             foo();
    

1) What's left of a bare function call is nothing - except for a blank line
that leads to the top indentation level. In other words, what's left of it is
the global scope. So, 'this' refers to the implicit global object in your
environment. (Alternatively, in strict mode, since nothing is to the left of
the call, 'this' is bound to nothing.)

    
    
        new Foo();
    

3) To the left of this function call is the 'new' keyword. So, 'this' refers
to the _new_ object that was just created for the constructor.

------
cwmma
Another exception, functions invoked with setInterval have 'this' be window,
even if they're invoked in context with it's own 'this'. This got me the other
day. [https://developer.mozilla.org/en-
US/docs/DOM/window.setInter...](https://developer.mozilla.org/en-
US/docs/DOM/window.setInterval#The_.22this.22_problem)

~~~
jQueryIsAwesome
A workaround that I like a little more:
[http://javascriptisawesome.blogspot.com/2011/11/setinterval-...](http://javascriptisawesome.blogspot.com/2011/11/setinterval-
with-context.html)

~~~
cwmma
There are totally a bunch of workarounds, it's just another exception to this,
I was using CoffeeScript so I was able to grossly simplify the MDN one
[https://github.com/calvinmetcalf/communist/blob/master/src/s...](https://github.com/calvinmetcalf/communist/blob/master/src/socialist.coffee#L9-L16)

------
tantalor
One exception to the first exception: in a function with "use strict", "this"
is _never_ the global object.

~~~
flebron
I don't see the "exception to the exception", he is saying that if strict mode
is on, "this" isn't the global object when saying foo(), it's undefined. And
that's true.

It's possible to both have "use strict" and "this" be the global object (i.e.
it's not true that it's _never_ the global object), as simple as...

    
    
      "use strict"; // global scope
      var x = 1;
    
      (function() {
      "use strict";
      return this.x;
      }).call(this);

~~~
raju
I am not sure that's quite what you want. Declaring x as a 'var' does not make
it a property on the global object. Your example will return an 'undefined'.

I think this is what you want

    
    
      "use strict";
      this.x = 1;
    
      var ret = (function() {
        "use strict";
        return this.x;
      }).call(this);
    
      console.log(ret); //returns 1

~~~
flebron
I wrote "// global scope" beside the first statement to signify that that
statement was run in global scope, same for the statement below it.

In global scope, the activation object is the global object, and so saying
"var x = 1" will make the global object have a property x equal to 1.

------
pixie_
var self = this; why do people bother with 'this'?

~~~
v413
IMO the use of self as the name of the variable referencing to 'this' is a
little dangerous, because in a function, if you miss the line var self = this,
self is a valid reference to the window object, so you will not get an
expected error for an undefined variable.

~~~
pixie_
Better a little dangerous 'self' than a lot of dangerous 'this.'

~~~
just2n
There's no real danger difference. If you implicitly do:

    
    
        var self = this;
    

When you need to use `this`, you just end up proxying the problem behind a
variable. If you don't understand what `this` is, it's not going to magically
start correcting your misunderstanding.

The only possible value it might have is when nesting functions if you refer
to `self` instead of `this` correctly, but this is the only case when I
actually use this pattern, and when I first create a nested function that
needs to use the parent's scope. Another option is to just `.bind(this)`.

In any case, I would disagree that one should try to avoid `this`. Instead,
one should educate themselves to understand what things in the language
they're using mean. And this subject is a great weeder question in Web
Engineer position interviews. If a person can't implement `bind`, can't
explain `call`/`apply`, what strict mode does, and what the `this` keyword
means in most contexts, they probably aren't strong enough in JS. This is one
of the most fundamental concepts in JS, it shouldn't be a source of confusion.

~~~
pixie_
I understand 'this', that's why I avoid it. All languages have their quirks,
and some programmers like to think they're 'smart' by taking advantage of
those quirks. Then when you or your team members run into problems you blame
the person and not the language, which you're right, but maybe you should of
just kept your code simple in the first place.

~~~
Zarel
I'm not sure I understand you.

Dereferencing things that aren't pointers leads to unexpected results in C.
Should we avoid dereferencing any variable in C?

I think of `this` in the same way - it behaves normally if you use it the way
it's intended to be used. In other words, don't try to read `this` in a
callback without binding it first, and you'll be fine.

Or are there other pitfalls I'm unaware of?

------
Whoaa512
Thanks, I love having simple one liners to remember complex concepts :)

------
slajax
Articles like this become more and more important as more and more developers
learn JS by way of frameworks like jQuery. If you want to understand "this".
Understand call() and apply() first.

------
ChickenFur
Thanks Henry!

------
wildranter
Tltr; _this_ is a mistake.

