6 ms·
Regarding components, states and encapsulation, also mind the much ignored `Object.prototype.handleEvent`, which has been around since 1997. I, know, it's OO, b
by masswerk 3y ago
Regarding components, states and encapsulation, also mind the much ignored `Object.prototype.handleEvent`, which has been around since 1997. I, know, it's OO, but it is actually simple:
function Counter(buttonElement) {
this.clicks = 0;
this.handleEvent = function(event) {
switch (event.type) {
case 'click':
this.clicks++;
console.log("I was clicked " + this.clicks + " times." );
break;
//handle any other event types
}
};
buttonElement.addEventListener("click", this, false);
}
const myCounter = new Counter( someButtonElement );
(In case you wouldn't know: if an object is used as an event listener, its `handleEvent()` method will be called with that object bound to `this`. In a way, arrow functions are working around what had been already solved by this mechanism.)
- imbnwa 3y agoSadly React disallows this pattern even though this interface is in the DOM spec
- masswerk 3y agoIn the context of coroutines, the nice thing about this is that – as a catch-all trap – it works much like an interrupt that is internal to that specific object. (Of course, only when the GUI thread allows for event processing.) On the one hand, this is pretty much the essence of what events should be about: invoking a dormant object (or context) by the means of a message. On the other hand, this inherent locality may pose a problem for any framework. (And – in the age of AI generated images – on the third hand, this is why I personally don't like frameworks that much.)
- kamikaz1k 3y agoIt doesn’t disallow it, it’s just outside of how the framework operates. If you really want to make the two talk, you could, with the cost of having to maintain it.
- MrJohz 3y agoI'm not entirely sure what this adds in this case, though. For example, in the code you've written, as far as I can tell there's no advantage compared to defining the function as a closure variable and using it directly, rather than defining it as an attribute on `this` and passing the `this` object around. In addition, with the `handleEvent` approach, you need to handle all events within a single function. But it's fairly easy to create multiple functions within a single function scope and pass them to different event handlers, thus avoiding the need for the large (and potentially error-prone) switch statement if you end up needing to handle lots of events. Have you found cases where `handleEvent` works better than just defining local variables within a function and just using those? It seems to me that you wouldn't even need arrow functions to take advantage of the natural power of closures in this context.
- masswerk 3y agoOne of the advantages is that this can be defined and handled on the prototype level and not just in the instance. Personally, I'd see the interrupt-like catch-all behavior rather as an advantage (all messages are received in a single slot), but this may be up to personal taste. And, while it's true that similar binding can be achieved using closures, this has also been true for arrow functions. It's just a convenient solution in the mindset of the original ECMA Script (ECMA 262-2). Regarding prototypes, mind how this shares methods between instances, rather than consuming (and locking) resources by individual closures created in each of the instances (which, when GC was still based on reference count, would also have meant memory leaks): function Counter(buttonElement) { this.clicked = 0; buttonElement.addEventlistener("click", this, false); } Counter.prototype = { reset: function() { this.clicked = 0; }, log: function() { concole.log("I was clicked " + this.clicked + " times."); }, handleEvent: function(event) { this.clicked++; this.log(); } };
- throw-the-towel 3y agoClosures really are poor man's objects.
- MrJohz 3y agoAnd vice versa!