I don't like the explanation as a set of piecewise cases. this just refers to the current object context. this refers to the window at the top level because you're operating within `window`. There aren't "simple functions" and "object constructor functions", just functions, and the `new` keyword executes the function within the context of a new object. Event listeners are not a special case, it's just that the callback is executed from the context of the event -- which makes the difference between `function (e) { this }` and `e => this` much easier to understand.
I agree. The key to grokking this is the difference between a function's execution context and its lexical scope. If you don't explain that I don't think you've explained anything, and if you do then there's no need to think about separate cases like the article suggests.
If you think of javascript code like an english sentence, then the function is the verb, the context (this) is the subject and the scope (arguments, closed over variables) are the nouns.
The unfortunate thing about the lengths people go to in order to try to "fix" `this` in event handlers is that it wouldn't be a problem if people just implemented the event listener interface correctly.
PSA Don't do this:
proto.foo = function() {
/* ... */
var self = this;
element.addEventListener("click", (function(event) {
self.iHaveAnUnhealthyObsessionWithLambdas(event.target);
}));
}
proto.iHaveAnUnhealthyObsessionWithLamdas = function(clicked) {
/* do something with clicked element `clicked` */
}
Do this instead:
proto.foo = function() {
/* ... */
element.addEventListener("click", this);
}
proto.handleEvent = function(event) {
/* do something with clicked element `event.target` */
}
The problem is that the approach is different depending on context. You are making use of the assumption that the addEventListener function knows to call the "handleEvent" method of the object in the second argument, and give it a proper "this" object. That's a big assumption, which should be documented in the code.
The code using "self" doesn't have this problem; it's more self-contained so to speak (no pun intended).
Well I don't see it used in a lot of code, so in that respect I think it is obscure. Also, using the "self" approach allows one to lexically bind to the enclosing scope, which aligns nicely with how most functional programmers think.
Agreed. Much prefer 'var self = this' style. Keep the model transparent for future maintenance.
One time I don't is in Jasmine, where they explicitly state that 'this' is shared across all 'beforeEach', 'it' and 'afterEach' calls. Which backs up your first point.
That's the fun part, because here you can code your event handling to read something more like a state machine. Here's a quick example in bogus code, adding and removing event listeners as we go along (and without keeping reference to all the callback functions):
class ElementDragger {
constructor(elm) {
elm.addEventListener('mousedown', this);
}
handleEvent(e) {
const elm = e.target;
switch(e.type) {
case 'mousedown':
elm.removeEventListener('mousedown', this).
elm.addEventListener('mousemove', this);
elm.addEventListener('mouseup', this);
break;
case 'mousemove':
elm.style.left = e.clientX + 'px';
break;
case 'mouseup':
elm.removeEventListener('mousedown', this);
elm.removeEventListener('mouseup', this);
elm.addEventListener('mousedown', this);
break;
}
}
}
That seems complicated, fragile, and bad for performance in a DOM. Event bindings are slow (or at least, used to be).
I don't know the purpose unbinding mousedown on mousedown - it only fires once per mousedown doesn't it?
Why not just stick with `elm.addEventListener('mousedown', this.handleMouseDown.bind(this))`? Where's the benefit other than making things more verbose?
Bind is less performant, because bind creates a new function with new context. At the framework level, bind is avoided at all costs. @wiredearp's approach is correct, because it only adds a single event listener, everything else is conditional.
If you think the above code has bad performance because "event bindings are slow" then your preferred form using `bind` is going to have all of that and more; it sidesteps nothing (except extremely fast switch case matching) and only adds overhead, both in runtime and memory costs.
> Where's the benefit other than making things more verbose?
To be clear what you're asking, are you saying that:
Switch statements are fine for simple tasks like the one in the example, especially earlier in a project where you do not know what you need in the future. You can always switch it to the correct pattern in version 2 as that way its better understood what hidden needs the code in question has, thus making it easy to pick a good OOP patern to replace it.
Then again, my jugment might be colored by working on codebases that are >21 years old.
It's however easy to read and that feels good if not right, since the common solutions to this imagined problem require substantial mental overhead as seen on https://hackernoon.com/rethinking-javascript-eliminate-the-s.... To promote "single functions" we could:
> No, that a switch statement is more verbose than a single function.
You're vacillating and applying an inconsistent standard. The switch statement is used where multiple listeners are being attached, therefore it wouldn't work with your "single function". You'd need multiple functions.
Give any example passing functions directly as the callback to `addEventListener` to demonstrate your case, please. The equivalent version that simply implements DOMEventListener will be less verbose, be lighter on resources (both with memory use and with runtime), and have no need for any this-binding workaround weirdness.
I guess the function could still be anonymous, but you will at least need to keep it assigned to some variable or property name. If you make use of the `handleEvent` pattern that @carussell suggested, you can however avoid having to keep track of all these callback functions since the listener can always be removed by passing `this` a second time:
> I don't like the explanation as a set of piecewise cases
We don't like it and it's redundant. One should learn the principles and return to this article to read it as a quiz and find out whether he got it or not.
Books like the excellent Javascript Allonge (free to read on leanpub) do a great job on explaining the context. If you need more hardcore stuff, "You don't know JS" will fit you better.
(Disclaimer: I'm not affiliated with any of the recommended books or their authors or leanpub or whatever.They just helped me a lot; and still do from time to time)
As an event listener "function(e) {this}" is not the same as "(e) => this". With the regular function "this" points to the element on which the event listener was attached to while with the arrow function "this" points to the context (i.e. "this") of its lexical environment.
Sorry, I don't follow your recommendation. Urgh, what a mess of a post.
All the (very valid) arguments that could be made for prototypical inheritance and functional programming style are drowned in a self-congratulatory fluff piece, full of marketing speech, substituting arguments by strawmen and namedropping, full of absolute claims and superlatives while demonstrating an rather pinhole view of computer languages, all the while not even giving a single practical example.
It doesn't bring anything (except a bit more performances when you create tons of objects, a setup that rarely matters unless we're talking video games or some very niche applications that somehow can't work with a subset of your data) but only create more cognitive load (bind, call, =>, closures using this, where Am I? is it a method or a function? Is it already pre-bound?).
Functionalities that create extra cognitive load and doesn't give you anything shouldn't be used.
As a related side rant, the `new` keyword, or equivalent, makes great sense in a manual-memory-management language like C, and it's an offense to sanity in a language like Java or Javascript. Factory functions should be the default everywhere. So any JS coding style that encourages `new` is a wildly bad fit to the rest of the language.
But it is important to admit the caveat, as you do, which is "when you create tons of objects".
Such situations are unequivocally in the minority (compared to line-of-business stuff where RAM and CPU more than sufficient to the task), but not the vanishing minority. So we do still need a good solution for those.
Rendering, simulation, sampling/signal-processing, parsing... the list goes on. This isn't truly systems-level code, but it's easy to generate a billion objects per second. So we do need patterns for doing this kind of programming.
Absolutely. The guts of the factory function should usually involve an object literal. Or in some cases, Object.create.
(If we're talking about Java, then obviously you have to have `new` somewhere, which is just one of the many shortcomings of Java, although obviously not a fatal one.)
I do really like JavaScript's ability to compose objects like that, and I feel that people interested in it as a language should definitely learn how to program in that manner. However, I suspect that for most people JavaScript is a means to an end, and it's more useful in a number of senses to try to write JavaScript more like other class-based languages. I mean, I feel like things like TypeScript sort of miss the point of having a dynamically typed language, but there is a solid case to be made for features like strong typing, especially as size and contributors go up.
I thoroughly understand `this` now after over a decade working in javascript, as well as thoroughly understanding `this` in Typescript which I use more now.
And I still make a mistake at least once a week. I know what I've done as soon as the code fails, but it's still so ridiculously easy to get into a context you didn't think you were.
Of all the mistakes made in javascript, `this` stands head and shoulders above everything else, with its arm round the prototypal class structure.
If there's anything that a decade of functional style being "the next big thing" has taught us, functional style is not "the next big thing" and most programmers don't work well in it.
i strongly disagree with this. half of my posting history on here is evangelizing FRP in javascript (in my case via bacon.js).
it has dramatically reduced the amount of time i spend on these and many other sorts of problems. honestly it makes programming way more fun. maybe haskell is a bit extreme for most situations but the concepts are not.
While you may love functional, and I'm not saying you shouldn't, I think you're strongly disagreeing with the statement you think I'm saying, "functional is bad", rather than the actual statement I'm making which is "functional programming's had many chances to become a mainstream language and it never takes off (outside a few specialities)".
What evidence do you have that functional is taking off? Since this board was around, every couple of years there's been a flurry of 3 months when a chunk of the community bangs on about functional programming.
First it was Lisp, then Erlang, then Haskell, then F#, then Scheme. I might have got the order wrong.
And it never, ever, ever takes off because while 10% of programmers find functional truly brilliant, the other 90% can't work with it.
For context, in that time Ruby (via Rails), Python (via Django and use in Science), javascript server-side (Node.js), Go, Swift, Rust and now possibly Kotlin have all taken off. Plus various other techs like NoSQL.
Hm. I guess it depends on your definition of mainstream.
In the front end space, functional programming is taking off, I think. Could be wrong, but React + Redux + immutablejs is a popular and very functional approach to UI.
Elixir appears to be on the same trajectory as Rails in it's early days. Anectodally, I know a lot of Rails devs and shops that are now primarily Elixir.
Most mainstream languages have adopted functional styles and best practices. Higher order functions, a general acknowledgement of the benefits of immutability, etc.
Fp may not be mainstream, whatever that means, but it's more popular than I can ever remember it being.
They ended up having to add classes (albeit as syntactic sugar).
Argue its advantages all you want, but I'd say that's representative of what a failure it's been. One of the last languages supporting prototype-based inheritance has basically given up on it.
Personally, I find it an awkward way to try and encapsulate code, generally, it has terrible performance to boot.
Was there ever any issues with prototype-based inheritance? I've always assumed that they added classes simply because of stubborn classical-based programmers who couldn't bother to learn JavaScript correctly.
The numerous overloads of 'this' is one of the things that turned me off from JS. It's great that bloggers explain the usages and how it works in different scenarios, but really the better solution would be to not have the problem at all. I would trade overloading for verbosity. An editor can easily squash the latter, where as a human has to train for the former.
But there is no "overload" to `this` in JavaScript. It works the same way every time. It's an implicit parameter that is passed when you call the function. It can also be bound, just like all the explicit parameters. The six ways the author presents are just an incomplete list of "Ways you can create an execution context in JavaScript".
This may be confusing to people who expect `this` to have a certain functionality when coming from a different language, but `this` is very consistent in JavaScript. It's just not the kind of consistency people seem to expect.
There's a great way to avoid having the problem - don't use the implicit parameter! What exactly is it giving you, anyway? In almost all cases where people fail to use `this`, they essentially create a function to pass it explicitly. Why not just do that from the get go?
EDIT: Rereading parent comment I realize you already know all the below, but maybe parent doesn't quite??
Original comment:
That's kind of fundamental expectation within JavaScript, though: 0 is a falsy value. The || doesn't check for null, it coerces the first expression to a boolean, and if it is true, returns the first expression. If it is false, then it returns the second expression (if I recall correctly!). If 0 being falsy is a problem, then the || might not be the easiest/clearest way to do what you need. Since you'd end up needing to nest some separate check for zero on the first expression. In which case you could just handle all your logic in that check.
Simple(r) explanation; this is whatever is "left" of the function call (i.e - obj.method() => this === obj inside the called method), unless you've used .bind/call/apply which explicitly sets what this should be via an argument.
If you're doing a direct function call like myFunc() there is nothing "left" of the function call. But you might think of it as actually doing window.myFunc(), which again explains why this === window. In strict mode this behavior has been "fixed" so that this === undefined.
Somewhat off-topic, but I saw your newsletter sign up form partway through the article and thought to myself "I would like to see new articles from this blog". The issue is I don't want to sign up for yet another email newsletter, and would much rather subscribe to an RSS / Atom feed. Do you have any plans to add one?
In Jerboa, my JS-inspired scripting language, there's an alternative to the "function" keyword called "method". The only difference is that "method" functions expose `this' and "function" functions don't.
This removes the need for the `var self = this' hack and all the related weirdness.
An amusing consequence is that if you declare a simple closure as a method, its `this' pointer will be the stackframe of the lexical context where it is called.
method test() { print(this.a); }
var a = 5;
test(); /* implicitly __stackframe__.test() */
(You should not actually do this, of course. It's fun though.)
The reason is straightforward: the `this' pointer is the object on whose lookup the closure was found...
So many new guides to `this` in the comments here. Not sure why this blog post exists either. I agree with most people that JS is confusing to people who are used to OOP programming in Python or Ruby, and that "this" is one of the most confusing parts. The best resource I've found is https://bonsaiden.github.io/JavaScript-Garden/#function.this . Free, online, concise, accurate.
Here's a fun one about `this` that you might not know. When running `eval`, `this` refers to the `this` in the calling context. Unless you alias the method. Then it refers to the global context.
class Test {
eval() {
return eval('this');
}
aliasEval() {
const e = eval;
return e('this');
}
}
const test = new Test();
assert.equal(test.eval(), test);
assert.equal(test.aliasEval(), global);
`this` was the single-most challenging thing when I was learning JavaScript organically by myself. Now that I get it, it's pretty simple, but I also love that with arrow functions, I've had to worry about the unboundedness of `this` far less.
Not an incorrect article, but my opinion is that the focus should be informing people to not use this at all and more education on immutable data vs confusions on this
The one place I've used "this" outside the context of a class is when I built a monad as an object and decided to use set the "this" context to be the monad. So, for example "return/unit/pure" (or whatever you want to call it :-) ) is available as "this.return". In that way the functions passed to "bind" can be generic and still build the correct monad.
There are other ways to do it, but this struck me as the first time I had fiddled with "this" and felt that it was a reasonable idea.
When you say "looks like an error", did you try running it? I assume you have a web browser handy.
All the examples in that section both look correct to me, and run as I'd expect in the JS environment I have closest-to-hand.
If you want help on the syntax, you should pose a more-specific question. Exactly what code looks like an error, and why do you think it's an error, and so on?
that is why sometimes we need to bind the this context in say like in jquery or react event handlers, they have different this every time! what a confusion isn't it?
I'm not sure I like this guide, because in several places it seems to imply the value of `this` is decided by where you define the function, which is only really true for arrow functions. For regular functions, unless you take control of `this`, it will be decided by the caller.
Best way I can think to describe `this`:
-----
1. Either you decide in advance exactly what you want `this` to be:
- Use `.bind()` on your function and fix the value of `this`
- Create an arrow function and get `this` from the lexical scope
- Alias `let self = this` in your desired scope, and only ever reference `self`
- Create a wrapper function which fixes the value of `this` (essentially, implement `.bind()`)
-----
2. Or `this` will be decided by your caller:
- Your caller will `.bind()` your function with an unknown value of `this`
- Your caller will call `.call()` or `.apply()` with an unknown value of `this`
- Your caller will attach your function to an unknown object, then call `unknownObject.yourFunction()`, setting `this` to `unknownObject`
- Your caller will call your function as a standalone function: `let newFunc = someObj.someFunc` - then call it, setting `this` to `global` or `window`
- Your caller will pass your function as a param to something like `setTimeout` and achieve the same effect, setting `this` to `global` or `window`
-----
Obviously, most of the time if you're going to use `this`, #1 is to be preferred, #2 is to be avoided, so it's imperative to decide in advance what you want `this` to be rather than allowing it to be decided by your caller.
(Unless that's absolutely what you want, and you have a good reason why -- like if you're writing a wrapper function which is agnostic to the value of `this` that's passed)
I always advise against calling your `this` alias `self`, because of https://developer.mozilla.org/en/docs/Web/API/Window/self - ie. if you missed out the `let self = this` line, then `self` will still work but it'll refer to `window`.
Surely this is going a little too far - there are tons of similarly innocuous names that will refer to globals if you forget to declare them. name, top, find, scroll, etc.
The real solution to the problem you're describing is strict mode and an editor that highlights undeclared variables!
You're right, of course, except that the entire design of `this` in Javascript is carefully tuned to make #2 easier and more frequent than #1. And we all gleefully exploit it when writing `[].slice.call(arguments)`.
I think it's an open question whether it was actually a horrifyingly bad design decision, or if it's rather that we're all too dumb to get it.