5 ms·
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,
by jpolitz 14y ago
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 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...
- jQueryIsAwesome 14y agoMaybe "call" and "apply" belongs to that list? 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 https://gist.github.com/4303394
- jpolitz 14y agoYeah, those were mentioned in the post as exception 2, but maybe I should make a note.
- deleted 14y ago[deleted]
- jQueryIsAwesome 14y agoYeah it's mentioned in the article, sorry.
- abecedarius 14y agoDo 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 14y agoYes 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.