7 ms·
“This” in JavaScript
- _mtr 12y agoNot mentioned are ES6's arrow functions that capture the `this` value of the enclosing context. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- jschrf 12y agoTypeScript 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.
- krilnon 12y agoMight 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'.
- jschrf 12y agoYeah 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.
- AnkhMorporkian 12y agoI think the new arrow functions are neat, but am I the only one who never really found it a hassle to throw a .bind(this) on a function?
- bshimmin 12y agoAside 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.
- acjohnson55 12y agoI 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.
- AnkhMorporkian 12y agoSure, my .bind was a little insensitive to those who had to suffer through ES3, but honestly I thought we were pretty much ignoring the 90s.
- bshimmin 12y agoYou say "the 90s", I say "2011". Potayto, potahto!
- jschrf 12y agoNot supported in ES3, IIRC.
- ulisesrmzroche 12y agoI think it adds too much line noise, especially if people start nesting callbacks.
- jMyles 12y agoThere'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."
- userbinator 12y agoI 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".
- deleted 12y ago[deleted]
- igl 12y agoIn short: this is a reference to a functions context. If no context is present it points to the global context or if encapsulated to undefined. context.func() //this == context func() // this == global
- drcode 12y agoThe 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". (great essay BTW on a hated subject :-)
- tricolon 12y agoI'm pretty sure "taxes you haven't paid for years but should have" would be worse.
- namuol 12y agoGreat reference doc! Grotesquely thorough.
- nmjohn 12y ago> 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.)
- wycats 12y ago> 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.
- _RPM 12y agoI 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.
- TazeTSchnitzel 12y agoIt's like an exhaustive, confusing list of examples rather than explaining briefly the very simple and largely intuitive reasons that lead to these examples.
- ams6110 12y agoI'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.
- nchelluri 12y agoThere's a nice link at the end of the post to another article that is simpler. I personally liked reading both. Here's the link: http://tomhicks.github.io/code/2014/08/11/some-of-this.html http://tomhicks.github.io/code/2014/08/11/some-of-this.html
- robin_carry 12y agoNice article...actually it helps in explaining new colleagues in our team. The link to examples is also good.
- couchand 12y agoThe 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: thing = {} thing.hasOwnProperty === Object.hasOwnProperty ...and so forth.
- deleted 12y ago[deleted]
- btipling 12y ago> 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.
- S_A_P 12y ago
- TazeTSchnitzel 12y agoThis 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.
- jeswin 12y agoYour 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, ..)
- dennisbest 12y agoIn other words, "this" is nuts!
- jqm 12y agoI liked this article. Yes, it was a bit repetitive and had lots of examples. Which is why I like it.
- ender7 12y agoThis 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`.
- hasenj 12y agoIt'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`: fn.call(object, param1, param2, ...);
- amitamb 12y agoI 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 http://www.manning.com/resig/ http://www.manning.com/resig/ 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".
- kristiandupont 12y agoI 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.
- CmonDev 12y agoIsn't ES6 backwards compatible?
- kristiandupont 12y agoSure, but the standard is going to influence the direction that the language evolves in, how most libraries are written and so on.
- CmonDev 12y agoI 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!
- wycats 12y agoI once wrote a description of `this` from the perspective of `call` as a "primitive": http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/ http://yehudakatz.com/2011/08/11/understanding-javascript-fu... It seemed relevant. :)
- vog 12y agoThe "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: someFunctionWithCallback(function() { this.something(...); }, this); Or: someFunctionWithCallback({ callback: function() { this.something(...); }, scope: this });
- the8472 12y agoes6 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.
- ulisesrmzroche 12y agoWhat? No, it's not an anti-pattern. It's about understanding functional scoping, JavaScript doesn't use lexical scoping.
- vog 12y agoNot sure where you got this from. JavaScript does use lexical scoping for almost everything, except for "this".
- deleted 12y ago[deleted]
- 12y ago
- jpolitz 12y agoThis topic has come up before on HN, and I ended up writing up a pretty comprehensive list of ways this can be bound, with references to the spec: https://news.ycombinator.com/item?id=4986125 https://news.ycombinator.com/item?id=4986125
- bshimmin 12y agoTony 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.
- john2x 12y agoHere's[1] an open-source book dedicated to "this". [1]: https://github.com/getify/You-Dont-Know-JS/tree/master/this%20%26%20object%20prototypes https://github.com/getify/You-Dont-Know-JS/tree/master/this%...
- mambodog 12y agoAnother 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.
- pavlov 12y agoMaybe, 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. But it's about 17 years late for that...
- hngiszmo 12y agoAs I'm doing my first serious projects in JS now, I'm thankful for the article and the simplifying corrections here. Java.this != JS.this
- madlynormal 12y agoCheck out Kyle Simpson's "You don't know JS" if you really want a clear understanding on "this" and how it relates to objects in Javascript. https://github.com/getify/You-Dont-Know-JS/tree/master/this%20%26%20object%20prototypes https://github.com/getify/You-Dont-Know-JS/tree/master/this%...
- chcokr 12y agoI'd say that one possible solution is to not use `this` at all. Same goes for `new` for that matter.
- eric_h 12y agoI've used this gist: https://gist.github.com/erichummel/2595398 https://gist.github.com/erichummel/2595398 a few times in interviews to see just how much of a javascript whiz candidates were. 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.
- indubitably 12y agoDoes `setTimeout` have a default value for the time?
- eric_h 12y agosetTimeout 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.
- ahoge 12y agoIt's clamped to 4. You can't go lower than that. 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.