Introducing ObjectHandler
since the discussion about a better Function#bind will probably never end, and since a must have dependency would be the ES6 WeakMap which is in any existent shim leak prone due lack of control via ES5+, I have proposed another way to solve the problem.
Above object is an Abstract implementation. In JavaScript we can borrow methods so whatever "class" would like to implement above behavior should extend the object or borrow those two methods and specify an events property.
Got it? Events property is simply an object shared through the prototype with properties name that are exactly the equivalent of DOM events name ... easy!
ObjectHandler IDL Like
/**
* interface ObjectHandler implements EventListener {
* void handleEvent(in Event evt);
* void remitEvent(in Event evt);
* attribute Object events;
* };
*
* @link http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
*/
var ObjectHandler = {
handleEvent: function handleEvent(e) {
var
events = this.events,
type = e.type
;
if (events.hasOwnProperty(type)) {
events[type].call(this, e);
}
},
// it could be called removeEvent too, as you wish
remitEvent: function cancelEvent(e) {
e.currentTarget.removeEventListener(
e.type, this, e.eventPhase === e.CAPTURING_PHASE
);
}
};
Above object is an Abstract implementation. In JavaScript we can borrow methods so whatever "class" would like to implement above behavior should extend the object or borrow those two methods and specify an events property.
Examples
Let's say we have a UI Class which aim is to react to certain events ... let's call it button:
function UIButton(parentNode) {
// add the node
this.el = parentNode.appendChild(
parentNode.ownerDocument.createElement("button")
);
// add quickly events to the node
for (var key in this.events) {
// add the listener ...
// NOTE: nothing to bind, no duplicated entries either
this.el.addEventListener(key, this, false);
}
}
// extends the class
Object.defineProperties(
UIButton.prototype,
{
// implements ObjectHandler
handleEvent: {value: ObjectHandler.handleEvent},
remitEvent: {value: ObjectHandler.remitEvent},
events: {value: {
// only once thanks to remitEvent
click: function (evt) {
alert("only once");
this.remitEvent(evt);
},
// some decoration on actions
mousedown: function (evt) {
this.el.style.border = "1px solid black";
},
mouseup: function (evt) {
this.el.style.border = null;
},
// recicle mouseup behavior
mouseout: function (evt) {
this.events.mouseup.call(this, evt);
}
}}
}
);
// example on window load
this.onload = function () {
new UIButton(document.body);
};
Got it? Events property is simply an object shared through the prototype with properties name that are exactly the equivalent of DOM events name ... easy!
Pros
- memory safe, nothing to bind, trap as bound, and stuff like this ... all instances will share same logic and bind is not even needed, aka: problem solved
- events are defined in a single place, easy to find, maintain, extend
- events are recycled, as it was as example for mouseout, though the instance
- most UI frameworks need the instance rather than the DOM node, to behave accordingly
- ObjectHandler can be used same way for "ObjectTarget", those listeners/able JS implementations, in order to uniform an event driven approach
- no risk to bind twice, no risk to remove the wrong callback, bound or not, it's the instance that makes the deal, not inline functions so it's less error prone
- performances in therms of both memory footprint and operation per each instance ... once again, no need to bind all methods to the instance itself ... what is in events is basically bound automatically through a single entry point, defined in ObjectHandler, for every single use case
Comments
Post a Comment