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.
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;".
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)
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.)
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.
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?
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.
So far, my code tends to not use this at all. However, I've not written any applications that go beyond a few hundred lines of JS (interestingly, most of these programs would have been a few thousand lines of Java, if I even bothered to try at all. For UI, the libraries for JavaScript far outstrip anything available for Java!)
I do seem to be gravitating toward an organization scheme that centralizes my applications data into a single place such that all moving pieces of the application get a shot at dealing with inbound messages in an orderly fashion. This allows me to decompose the application into a very small number of function types, each of which has an explicit kind of responsibility.
The only time I've been tempted to go back to OOP has been to write (pure!) functions that seem to just beg for it - complex validation routines in particular. But using OOP for the app as a whole seems to not only be unnecessary, but positively undesirable.
This is why I avoid using "this". Placing this comment next to any of the 9 points causes the comment to mean something different. However, "this" could be useful in circumstances where that is the exact effect desired. Even in such cases, the relevant object can be made explicit as an argument.
Some time back, I had to explain to some people how to think about "traditional OO" in JS, which I tried to make systematic in a post [1]. (Not trying to self promote here, but most other presentations I've seen start with the prototype mechanism. "this" is not brought in until much later in the post.)
When using addEventListener, "this" is not necessarily bound to the DOM node. You can also pass an Object whith a "handleEvent" function as attribute, instead of directly passing a function.
For 6), a question, is .bind not just returning a new function, which will .call your provided one with the supplied "this"? That is, I think it's better to reason about it not as an exception to the usual semantics, but as something that can already be done by any coder in the language itself, using the usual semantics.
On a pedantic note, due to complications with the new() operator, you can't actually implement .bind() in JS using only .call() and .apply() and get the prototype of the resulting objects right.
My comment was wrong, I was mis-remembering a bug that I'd seen before. You can get everything correct with the prototypes, but you cannot perfectly emulate it.
The only thing you can't do with JS emulation of .bind() is the ability to create a varargs constructor (https://bugs.webkit.org/show_bug.cgi?id=26382#c29). But at the same time, I don't totally grok that example yet. The relevant bit of the spec is http://es5.github.com/#x15.3.4.5.2, which describes the [[Construct]] behavior of .bind().
Thanks for the thorough response! I didn't know about point 9: using strict mode to prevent prototype functions from converting primitive types to objects. That weird behavior has bitten me a couple of times.
Function.prototype.call(this, argument0, argument1...)
Function.prototype.apply(this, [arguments]) // array for args.
In a related note I created a variation of .bind that can have its bounded arguments an 'this' overwritten called mixbind, and also the methods .mixcall and .mixapply that can be used to overwrite arguments too (you can use NULL or undefined to left holes):
https://gist.github.com/4303394
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.
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.
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'.
Certainly. Why should some state be teleported in magically while other state (the argument 'e' in the above example) has to ride the bus? Does it belong to a different class of Being? I don't think so. This forces me to spend precious brain cells remembering which things go in which buckets and what the rules are for accessing the buckets - i.e. busywork - rather than the problem at hand.
The easiest thing is to explicitly bind to just that state you need and ignore everything else. That's more or less what the argument "e" offers: it's a bag of all the goodies you might need while handling your event. Clearly, therefore, the DOM element emitting the event should be available through that same mechanism – and as you generally can get everything you need in that department through things like e.target, I find it simplest to remain blissfully ignorant of 'this'.
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.
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);
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
Fair point, but I thought it was clear I was referring to the first "exception", that is, calling a function like "foo()". Your example, while interesting, doesn't apply.
I'll be more clear:
> When there is no ‘.’ the keyword ‘this’ is bound to the global object window.
because you sometimes want to refer to the original 'this' reference inside an inner nested function scope, where the actual 'this' keyword is rebound to the context of the inner function.
function outer() {
var outer_this = this;
var inner = function() {
var inner_this = this;
// ...
}
}
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.
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.
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.
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.
The problem with `self` is that it is already a predefined global variable in the browser pointing to the global object :)
And btw, the `this` situation with javascript is not that bad :) use bind - either the Ecmascript 5 version or shimmed and you will be fine. Not much drama.
No but this is still bound at call time, so `self` will be foo in foo.play() just as this, so that's basically the same thing + a standard variable assignment to get the setTimeout working.
On a sidenote, I'm trying to get away from using self, and do object.bind in all my setTimeouts. To my mind, it leads to much cleaner code.
The nice thing about it is that it allows you to break out of nesting hell while still being prototyped... e.g. window.setTimeout(this.foo.bind(this), baz);
Since .bind is essentially currying, you could imaginably do window.setTimeout(this.foo.bind(this, bar), baz) as well, if foo is dependent on bar (timing out a request `bar' or something like that).
Of course, taking the method out of the object will produce a different result. But if you are doing something weird like that you should know what you are doing.
I don't think it's _that_ weid considering JS is a language where functions are perfectly normal values. Someone unfamiliar with the semantics of "this" in JS might expect that:
Ho, you beat me to it with the Python reference (see my other comment in this thread) :)
I don't know if it's really that bad that JS returns the unbound function when doing `obj.someFunc`, as it is consistent with any other property access: it returns the same thing that was assigned to that key in the object, or at some point in its prototype chain.
The really broken behavior, at least for me, is that when doing `var f = obj.someFunc(); f()`, the "this" gets bound to "window" in the f() call, instead of being null, or better yet raising an error whenever referenced, like an undefined variable.
In what other language you have direct access to methods as first class objects to do an immediate execution of a method returned by an execution container (parenthesis in JS) ?
> In what other language you have direct access to methods as first class objects to do an immediate execution of a method returned by an execution container (parenthesis in JS) ?
Not sure if i understand the question. This seems to work in Python:
s = "Hello"
up = True
(s.upper if up else s.lower)()
Not that it's a very pythonic piece of code, but it works, and i would expect many other languages support something similar.
Anyway, that's tangential. And i wasn't discussion what "most people would" do either. What i was trying to say is that by aliasing "var self = this" you're not automatically immune to the quirks of "this" in JS.
For consistency and to avoid populating the scope with named variables, look at how jQuery works for good examples of how to use 'this' (the puns are infinite with this)
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.
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:
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.