8 ms·
JavaScript: Clarifying The Keyword ‘this’
- Whoaa512 14y agoThanks, I love having simple one liners to remember complex concepts :)
- tantalor 14y agoOne exception to the first exception: in a function with "use strict", "this" is never the global object.
- flebron 14y agoI 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 14y agoI 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 14y agoI 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.
- tantalor 14y agoFair 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. False if the function has "use strict".
- jrajav 14y agoYou 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.
- ChickenFur 14y agoThanks Henry!
- ender7 14y agoSadly, 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> });
- lucian303 14y agoUnfortunate? Would you prefer to bind that yourself?
- gruseom 14y agoWould you prefer to bind that ['this'] yourself? 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'.
- lucian303 14y agoAgreed. Too bad we're stuck with Javascript. EDIT: I meant that as a pronoun.
- flebron 14y agoThat'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.
- jpolitz 14y agoThe 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 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 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 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 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 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...
- cwmma 14y agoAnother 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.setInterval#The_.22this.22_problem https://developer.mozilla.org/en-US/docs/DOM/window.setInter...
- jQueryIsAwesome 14y agoA workaround that I like a little more: http://javascriptisawesome.blogspot.com/2011/11/setinterval-with-context.html http://javascriptisawesome.blogspot.com/2011/11/setinterval-...
- cwmma 14y agoThere 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/socialist.coffee#L9-L16 https://github.com/calvinmetcalf/communist/blob/master/src/s...
- pixie_ 14y agovar self = this; why do people bother with 'this'?
- shabble 14y agobecause 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; // ... } } http://stackoverflow.com/questions/4886632/what-does-var-that-this-mean-in-javascript http://stackoverflow.com/questions/4886632/what-does-var-tha... has some more details.
- pixie_ 14y agoOf course there are exceptions to the rule, but the rule should still be - avoid 'this.'
- jQueryIsAwesome 14y agoFor 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)
- jpolitz 14y agoI'm confused... doesn't that just reduce the question to "what is the current binding of self"?
- jQueryIsAwesome 14y agoAfter assignment "self" does not change even if "this" does. var player = { play: function(){ var self = this; setTimeout(function(){ console.log(self); }); } }
- marcusf 14y ago
- wildranter 14y agoTltr; this is a mistake.
- ryanjodonnell 14y agoPlease 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.
- drblast 14y agoJavaScript 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.
- mistercow 14y agoThe ability to wrangle `this` via fat arrows is one of the nicest things about CoffeeScript.
- josteink 14y agoThe 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.
- slajax 14y agoArticles 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.