“This” in JavaScript(bjorn.tipling.com) |
“This” in JavaScript(bjorn.tipling.com) |
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%...
Also, it will probably be a long time until it can be widely used, given the existence of certain browsers and versions.
But first, let me fix some errors in your code.
You probably meant to write syntactically correct code, so first line changes to following:
o={ f: function() { setTimeout(1000,console.log(this)) } }
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.So the code changes to:
o={ f: function() { setTimeout(function() { console.log(this); }, 1000); } }
o.f()
Okay. So what happens now is that- You create and object with property 'f'
- You call the function stored within that property
- Within Execution Context of that function call, `this` is going to be equal to our object. Note that we have not yet used `this`.
- We call setTimeout, passing it function as a callback.
- After one second, that function is called, with new Execution Context, not equal to the first one. `this` there is equal to global scope variable.
Basically your code is doing this right now:
o.f = function(){
console.log(this); // logs `o`, returns `undefined`
setTimeout(1000, undefined);
});
If you did this: o.f = function(){
setTimeout(1000, function(){
console.log(this);
});
};
Then it'd be `Window` as in rule #2.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.
But it's one of the weirdest thing in javascript, and I'd advise to forgo using 'this' in any situation that doesn't absolutely need it.
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.
[0] https://www.youtube.com/watch?v=PSGEjv3Tqo0&noredirect=1
You are mistaken, "this" is not an object nor a variable, it's a keyword and behaves differently than variable scope. Consider closures for example.
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.
It enables some rather elegant patterns, actually.
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.
function foo() {
var bar = function() {
console.log(this);
};
return bar.bind(42);
}
foo().call(1337); // prints 42
...which behaves as expected, so I'm not sure what you're getting at?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.
At that point you might as well just redesign the language from scratch, which maybe you'd appreciate.
Guess I'm just not feeling the hate on this one.