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.1) The keyword "this" refers to whatever is left of the dot at call-time.
2) If there's nothing to the left of the dot, then "this" is the root scope (e.g. Window).
3) A few functions change the behavior of "this"—bind, call and apply
4) The keyword "new" binds this to the object just created
So if you're using the value of "this" in someFunction...
thing.someFunction(); // this === thing
someFunction(); // this === Window
new someFunction(); // this === the newly created object
It's as simple as that. It's a very useful keyword.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 o={ f: function() setTimeout(1000,console.log(this)) }
o.f()
http://jsfiddle.net/5bh7yot5/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.
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.
obj.method();
is a sugar for obj.method.call(obj);
Similarly, this picture helped me understand `bind`:http://i.stack.imgur.com/StZOr.png
The a-ha moment for JS is when you realize it's a way simpler language than you thought it was.
new method()
is syntactic sugar for something like var _tmp = {};
_tmp.__proto__ = method.prototype;
_tmp.call(method);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.
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, ..)
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`.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, ...);https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
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 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.)
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.
(great essay BTW on a hated subject :-)
context.func() //this == context
func() // this == global
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.
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.
Edit: in both cases the result is the same in most browsers.
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."
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 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
});https://www.youtube.com/watch?v=t5EI5fXX8K0&list=PLB63C06FAF...
strict mode + arrow functions bring a little more sanity to JS.
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".
But it's about 17 years late for that...
// 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.
It seemed relevant. :)
[1]: https://github.com/getify/You-Dont-Know-JS/tree/master/this%...