The author critically misunderstands the way that `this` gets set, and in doing so has developed a significantly overcomplicated mental model. This is exemplified in the statement:
You can use this in any function on an object to refer to other properties on that object. This is not the same as an instance created with new. ... Note, there was no use of new , no Object.create and no function called to create obj.
This is exactly the same behavior that you see on an object method reference, and drawing any distinction at all makes understanding the behavior of this harder than it needs to be.
In nearly every case (with the exception of bind, call and apply) the this variable is set at the CALL SITE of the function, NOT THE DEFINITION. Note that in the three other cases, you still aren't setting this at the definition.
The reason you get this behaving as the author describes on objects created with new is only (as the author nearly, but not quite, realizes) because you called the function in the form:
thing.method()
Specifically, it is the object reference that sets the this context within the method call.
You can be sure that the object literal case is just the same. You don't need to call new to get an object reference that has a prototype chain: namely, an object literal is instantiated with the prototype Object. You can verify this is true with a simple:
I see that some people are slowly redefining the word "simple" as applied to programming languages. A 4-point bullet list that still requires knowing about typical caller behavior is hardly "simple".
Actually, it's not about typical caller behavior. When you write a function, what 'this' is is going to depend on how your function is called. If you don't want caller behavior to affect your function, don't use 'this'. If you want to allow callers to choose what object your function should act on using a variety of convenient syntaxes, then write your function to use 'this', but be aware of all the ways a caller might set it.
Exactly. Once you understand underlying concept, `this` is not complicated or weird.
Small addendum to your list: "whatever is left of the dot at call-time" is a nice way to explain "base reference" concept, but be wary of non-trivial constructs:
(f = thing.someFunction)(); // this references global object
(function(){return thing.someFunction }())(); // this references global object
eval('thing.someFunction')(); // this references global object
I don't think a project is "wrong" if it is working.
Also these a just opinions, but I think it's counterproductive.
I feel it's the same as class systems with inheritance and lots of OO properties implemented. It's not wrong, but it's so much overhead, so easy to shoot one's foot, for so few returns. And there's a class syntax coming to ES6, so I'm clearly in the minority.
For a discussion on the "this" use, there is an interesting talk[0] by D.Crockford on the subject, at about 8 min in (but I'd watch the whole thing). I don't agree with everything he is advising, but I think he has pretty compelling arguments overall.
There's a lot of things in js that are not necessary to write good code, and avoiding them can reduce a lot of the complexity IMO. Some people are OK with complexity and want expressivity, I'd prefer basic and predictable easily behaviours.
Then, you probably meant to call console.log after one second, not running it immediately and passing result to timeout argument, and passing 1000 as a callback argument.
The way you've written this code, `this` refers to `o`, as it has been evaluated at the time of execution of `f()` (first case) rather than inside the `setTimeout` callback, at which point it'd be `Window` (second case). So yes.
> The author critically misunderstands the way that `this` gets set...
I don't actually. (I'm the author) I know that the this key word is executed at run time to figure out what this is. It is true there are simpler ways to explain this and this blog post isn't that. I link to such a post at the bottom of my own. These are just some examples. There's also more to that blog post than what everyone is discussing, like returning from a constructor and global this in node.js and accessing this in eval and more. Anyway, I didn't submit this to HN and hadn't intended to. I also didn't intend to sit here tonight and put on a thick skin to deal with all this criticism for something I wrote months ago.
Don't take the criticism too hard. I enjoyed the post. I don't regularly write JavaScript so I found many points helpful. There is potential for pedantry here on HN, so dont take offense. I appreciate the post...
The article was a nice refresher about 'this' subtleties, but it put too much work into contrasting it against Java's this, instead of just laying out the actual JS rules.
To me, 'this' is JS is a lot more self explanatory than this is Java. And your article doesn't make that apparent. In JS this is just another object, like any other object. It follows the exact same scoping rules as every other object.
And the tragic thing about "this" being a magic keyword that looks up a dynamic value in the runtime, instead of a normal lexically scoped variable like it appears, is that 90% of the time "this" is exactly the thing you want a closure to close over, so you have to do ridiculous stuff like "var self = this;".
Even knowing this rule very well and being totally hard core OCO (Obsessive Compulsive ORDER, not Disorder) about the code, I still make "this" mistake ALL THE TIME, so whenever something weird happens, "this" mistakes are the first thing I look for.
"this" is such a terrible design flaw, it bites me even when I'm expecting it.
Patterns which could have been just as easily implemented using another more explicit technique for dynamic binding (like simply passing the dynamic parameter to the function as a normal argument) without fucking up the entire language design with invisible implicit magic, and dooming millions of programmers to repeatedly make difficult to detect, subtle mistakes, bugs and security holes.
Please give me one example of using "this" outside of lexical context, that is impossible or tangibly inconvenient to do by some other technique that JavaScript already supports.
Well, you could pass around the object but then you'd have to come up with a new object-literal syntax because `this` won't exist any more, unless you're planning on keeping it around but keeping it lexically scoped, in which case you have to stop using object literals as traits and prototypes.
At that point you might as well just redesign the language from scratch, which maybe you'd appreciate.
I agree. The fact that you have to write library code defensively to still work depending on how your method's call, or that you have to use an awkward bind to preserve the `this` context of a method is so annoying and error-prone to me.
Even when you remember to perform the awkward bind / Function.prototype.call / Function.prototype.apply / var self = this; you still may already be inside of another context where this is not correctly defined. So then your code LOOKS even more like it will work thanks to the cargo cult magic ceremonies you've performed perfectly, but in the wrong place. It's like going into the bathroom like you're supposed to, but then taking a shit on the floor right next to the toilet, then flushing.
You don't have to do that, you can tell a function what to use by using 'call' or 'apply'. Some people even use bind, but I think it adds too much line noise.
You don't have to do what? Make mistakes? Of course I don't have to make mistakes, but I do all the time, and so do other people.
You have to REMEMBER that you need to explicitly and inconveniently tell the function which "this" to use, by drilling down into Function.prototype.call/apply, even though it LOOKS like it will simply work like any other variable, which it doesn't.
Please consider that programmers are not perfect, and do not have infinite time or unlimited memory or perfectly focused and undistracted attention, and programming languages are user interfaces for imperfect humans, that should minimize the likelihood of errors, not set traps for less experienced programmers to make obvious mistakes, just so that more experienced programmers can gloat over how much smarter they are for having memorized every detail of the language spec. (-; I'm looking at you, automatically inserted semicolon! ;-)
And my point is that I AM an experienced programmer who has memorized every detail of the JavaScript language spec and uses it all the time, yet I STILL make "this" mistakes AGAIN and AGAIN. While on the other hand, I don't think I've ever made a "self" mistake with Python.
The way I think about it ('this' being like any other object), closures are just supplied a default 'this' object (window, in the case of web), and instead of providing a this argument via the argument list, you can choose it with the apply/call/bind functions.
I like your article and it fits well with my usual methodology of grokking something, namely running a bunch of tiny examples until I see the patterns.
Yes - the trick with JS is to realize it has this functional core, and every object has an __proto__ property, and then most of its syntax is syntactic sugar over the top of that.
new method()
is syntactic sugar for something like
var _tmp = {};
_tmp.__proto__ = method.prototype;
_tmp.call(method);
This post is way, way too long. Rather than explaining the simple principles that lead to the behaviour JS's this has, the post just lists example after example.
JS 'this' is a variable defined within a function. If that function is called as if it were a method, e.g. obj.somefunc(), 'this' is that object, obj. Otherwise, 'this' is the global object (quirks mode) or undefined (strict mode). If a function is called with the new keyword, 'this' is set to a new object whose prototype is set to the property named 'prototype' on the function.
The prototype of an object is a fallback: if you try to read a property on an object and it lacks such a property, it'll grab it from its prototype (or its prototype's prototype etc.) if it has it. If you write to or create a property on an object, it always goes on the object and won't touch the prototype.
The weird behaviour for DOM events isn't weird. It just calls the onclick method as a method.
Your explanation is way simpler to understand than the lengthy original article.
Maybe one addition: the value of 'this' inside a function FN can also be set by a caller of FN by using the form FN.call(this-ptr-value, arg1, arg2, ..) instead of FN(arg1, arg2, ..)
This is a pretty long article. The concepts you need to know aren't so long:
There are three ways to invoke a function. The meaning of `this` depends on which method was used:
- If a function is invoked in the form `foo.func()`, then the value of `this` is `foo`.
- If a function is invoked in the form `func()` (sometimes called "bare"), then the value of `this` is the "root object". In browsers the root object is `window`, in Node this it's the `global` object [0]. It's easier to make a bare invocation than you think:
var bareFunc = foo.func;
bareFunc();
- If a function is invoked via the `call()` or `apply()` function, then the value of `this` is whatever the invocation specifies. For example, in `func.call(foo)` the value of `this` will be `foo`.
If you ever pass a function to something else as a callback, you have no guarantee what the value of `this` will be when it is called. For example, if you register a callback for a click event, the value of `this` is whatever the caller wants it to be (in this case, it'll be the DOM element that's emitting the event):
function MyFoo(elem) {
elem.addEventListener('click', this.onClick);
}
MyFoo.prototype.onClick = function(e) {
// `this` is whatever the caller wanted it to be
}
You can force `this` to be a specific value by using the `bind()` function:
function MyFoo(elem) {
elem.addEventListener('click', this.onClick.bind(this));
}
MyFoo.prototype.onClick = function(e) {
// `this` has been bound to what you think it should be.
}
[0] However, if you're in strict mode, then in either case `this` will be `undefined`.
It's also worth noting that `bind` is not all that special; it simply returns a function that calls `apply` and passes the `this` object you specified.
I generally think of `this` as an invisible (sneaky) function parameter. It can be made more visible by using `call`:
TypeScript has these and they're marvelous. They make writing functional style code very enjoyable and not having to capture `this` yourself is alone justification for this developer to never go back to pure JavaScript.
Might you go back when ES6 is widely supported by browsers / Node? I don't mind either way, but since the parent comment mentioned that arrow functions were coming to JS, it was interesting that you specifically said 'never', rather than 'until ES6'.
Yeah I realize that may not have been the clearest statement, thanks. While ES6 is nice, it just doesn't have the elegance and utility of some of the other TypeScript things like generics and the interfacing system.
Also, it will probably be a long time until it can be widely used, given the existence of certain browsers and versions.
Aside from the fact that your "never" somewhat dismisses the first however many years of web development (up to IE9) when `Function.prototype.bind` couldn't universally be expected to be supported, surely having a nice piece of syntax which is both shorter than writing out `function` and serves the purpose of binding the function in the way that, a good majority of the time, you actually want it bound, is a good thing?
As someone who's spent a lot of time writing CoffeeScript, I think ES6's fat arrows are a great thing, though I have my usual concerns about their confusing the hell out of people who may well have been writing JavaScript for a long time but in environments where they don't necessarily get exposed to new and exciting stuff. But hey, that's progress, I guess.
I agree. Fat arrow is a massive improvement. Not just for its extremely logical handling of "this", which 95% of the time is the behavior I want, but also because it eliminates a massive amount of syntax noise when programming functionally.
> JavaScript is not such a language. ... There are many “gotchas”
I don't disagree, like all languages javascript has its quirks (more than some, fewer than others, all depending on a given developers perspective) but I fail to see this conclusion being supported by the article itself.
Basically every quirk in it was a result of 'use strict' preventing a developer from leaking variables (and thus `this`) in ways they shouldn't be doing - which results in slightly different behavior when strict mode is enabled. The only real quirk I see here is the fact that strict mode isn't enabled by default (or better yet not even an option to turn off) but that is because it would kill backwards compatibility.
'this' in actuality is pretty straightforward - unless you make it complex. (Which javascript does make it very easy for you to do, which means bad code will be written doing just that. But bad code is bad code regardless.)
When you define a new function, the contents will have a different scope and 'this' will be different. If you want to access the parent this in a nested function, you either call the function with the 'this' bound, or you do `var self=this;` in the parent scope, and use 'self' in lieu of 'this'.
That is pretty much it - I can see how it is a bit tricky at first, but after spending a bit of time working on javascript it really isn't something you have to consciously think about too often.
I don't think it is inherently bad, just different. Back when I was writing Java I would have told you I like their approach better, but now after writing almost exclusively javascript for the last year or so, I would say I like the javascript 'this' better. At the end of the day they are just different and a developer needs to learn the intricacies of whichever language they are developing in. (Since criticizing javascript is trendy on hn these days, if you want something to be critical of javascript about that can objectively be explained, go with the lack of static typing or the related quirky type coercion in equality checking resulting in (2 == [2]) => true.)
> The only real quirk I see here is the fact that strict mode isn't enabled by default (or better yet not even an option to turn off) but that is because it would kill backwards compatibility
Worth noting: modules in ES6 are "strict by default", which means that most new code will be in strict mode, without compatibility hazards. Transpilers emit `"use strict"`, so anyone using one of the ES6 module transpilers is already writing 100% strict code.
The title of this post alone fills me with anxiety and loathing. The only title I could think of that would be worse for a post is "Taxes you've been paying for years but didn't have to".
I skimmed the article. I began to get anxiety once I realized how long it was. JavaScript is a very simple language. `this` in JavaScript is easy to understand. Long posts like this give me anxiety.
It's like an exhaustive, confusing list of examples rather than explaining briefly the very simple and largely intuitive reasons that lead to these examples.
I'm reasonably smart, but I don't ever remember the various contextual meanings of "this". Maybe because when I use javascript I try to use frameworks that hide the need to think about it. It's a wart on the language in my opinion.
I hated JS in the beginning, trying to make write it more like I write C# or C++ (I have experience with other languages, but the syntax lead me to believe that this style would be best suited). I wrote "self = this" a lot.
Now, I have adopted a much more functional style and I find JS increasingly pleasant to work with every day. To the point where many of the new ES6 features are a bit worrying because it looks like they want to take it in the direction of what I wanted it to be when I started. At this point, using "this" or "prototype" is almost a smell -- they're useful at times but whenever I use them something in the back of my mind tells me that I could probably be doing something more elegant.
I agree, it would be better if JavaScript was made even less human-friendly than it is now.
This way the transpilation approach would become mainstream and people would get a real choice of language instead of an arithmetic average of language preferences.
Thankfully, the Asm.js is making some important right steps in that direction - and boosting the performance as well!
The basic gist of the interview question is "what is output to the console when this code is run?"
It's obviously intentionally obfuscated, so even if the candidate got it wrong (most did), subsequently talking through the solution told me a lot about how good a candidate was at static analysis and talking through a problem.
setTimeout with no timeout argument simply schedules the provided function for when the interpreter is next idle. Underscore.js wraps a similar unqualified call in _.defer (last i checked, anyway; they might now provide it with a very small number or 0 for the timeout).
Edit: in both cases the result is the same in most browsers.
There is `setImmediate` for making something run the very next cycle. However, only IE10+ supports it and the other browser vendors are against it. You can use abuse `postMessage` to get a similar effect.
There's something to be said about the distinction between "this" and "self" as names for the self-referential instance object. While "self" emphasizes mutability and introspection, "this" evokes a more material, evidentiary abstraction.
When I transitioned from PHP to Python, the change in nomenclature (albeit only a social norm in Python) was a big part of what helped me think bigger about this concept.
To this point, this read might have been easier to digest had it started with the section "object this."
I personally don't find the terminology has much significance; it wouldn't matter if it was named "the", "this", "it", "my", or "object", it all refers to "the object instance upon which this method is invoked".
Maybe it's just because I'm familiar with C where the equivalent of a "this" reference often has a different name depending on the "class", e.g. "struct Window * w" or "struct Button * b".
The "this" keyword in JavaScript is a well-known anti-pattern. Although it can be explained with a few rules, it becomes cumbersome quickly.
The anti-pattern around "this" is well-known for decades. For example, SICP explicitly mentions that anti-pattern. Of course, it doesn't refer to JavaScript, but to some other old programming language which had a keyword with very similar issues. I think it's not a hyperbole to say that in this regard, the JavaScript/ECMAscript language designers haven't learned from the past.
The main issue is that "this" violates lexical context.
Fortunately, the lexical context is easily restored by declaring a normal variable, usually named "me", and using the fact that variables have always lexical scope in JavaScript (as it should be):
var me = this;
someFunctionWithCallback(function() {
me.something(...);
});
Another workaround is adding a "scope" argument to functions which take callbacks:
es6 arrow functions preserve the lexical context for this, alternatively you can bind functions to the current this so it remains the same as the outer function scope.
strict mode + arrow functions bring a little more sanity to JS.
I understood these concepts by reading this book. It is great book for anyone wanting to go from intermediate to advanced or may be even beginner to advanced level
You can go on using Javascript for years without understanding some basic concepts like "value of this does not depend on where that function is defined but the way it is called".
Maybe, rather than overriding the C++ / Java keyword with a different meaning, this should have been called something completely else in JavaScript. I think context would have been more descriptive.
Another way of thinking about it is that it's kinda like Function.prototype.call is being used implicitly at the call site to set the 'context' (the 'this' value):
// assuming in each case
var o = {}
var o2 = {}
var fn = function(){}
// 1. bare function call
fn() // this == undefined in strict mode, global in non strict mode.
// 2. calling with Function.prototype.call
fn.call(o) // this == o
// 3. 'method' call (calling an object's function property)
o2.fn = fn
o2.fn() // this == o2
// equivalent to
fn.call(o2)
// 4. calling object's function property with Function.prototype.call
o2.fn = fn
o2.fn.call(o) // this == o
// 5. new
var o3 = new fn() // this = o3
// equivalent to
var o3 = Object.create(fn.prototype)
fn.call(o3)
// 6. calling function bound with Function.prototype.bind
var fn2 = fn.bind(o)
fn2() // this == o
// equivalent to
var fn2 = function(){ fn.call(o) }
fn2()
// 7. calling object function property which is a bound function
o2.fn = fn.bind(o)
o2.fn() // this == o
// equivalent to
o2.fn = function(){ fn.call(o) }
o2.fn()
Basically you should think of functions (and 'methods') as not being intrinsically bound (as in binding-of-'this' bound) to anything.
If you think of a 'method' (function property) as being bound an object purely by being 'attached' to it then you are gonna have a bad time. Instead, think of binding of 'this' as usually only happening at call time, to the thing you are 'calling the function off of'.
In reference to case 1 (bare function call), this is the same behaviour which occurs when as defining an anonymous function inside a function which has 'this' set. Just don't use 'this' in this case, it doesn't make sense. Defining a _this or self variable in the parent function is the standard practice to deal with this case, or in ES6, Coffeescript etc. you have the => fat arrow to implicitly do that for you.
Tony Hoare has famously described null references as his billion dollar mistake. Given how often we see articles attempting to explain `this` in JavaScript (indicative, therefore, of the general level of confusion around it), I wonder if perhaps we should be starting to think about `this` in similar terms.
You can use this in any function on an object to refer to other properties on that object. This is not the same as an instance created with new. ... Note, there was no use of new , no Object.create and no function called to create obj.
This is exactly the same behavior that you see on an object method reference, and drawing any distinction at all makes understanding the behavior of this harder than it needs to be.
In nearly every case (with the exception of bind, call and apply) the this variable is set at the CALL SITE of the function, NOT THE DEFINITION. Note that in the three other cases, you still aren't setting this at the definition.
The reason you get this behaving as the author describes on objects created with new is only (as the author nearly, but not quite, realizes) because you called the function in the form:
Specifically, it is the object reference that sets the this context within the method call.You can be sure that the object literal case is just the same. You don't need to call new to get an object reference that has a prototype chain: namely, an object literal is instantiated with the prototype Object. You can verify this is true with a simple:
...and so forth.