Skip to content

Instantly share code, notes, and snippets.

@Munawwar
Last active March 5, 2016 17:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Munawwar/ea0551bb4d3cdaf4ce42 to your computer and use it in GitHub Desktop.
Save Munawwar/ea0551bb4d3cdaf4ce42 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
</head>
<script>
/**
* The problem: Binding functions (using function.bind()) and adding listeners is messy,
* since a bind creates a new function everytime and one needs to keep reference to the new function.
* When having many event handlers this gets messy.
*
* In the solution below I am adding on() and off() methods to all HTMLElements.
* However one could achieve the same without touching native objects.
*
* This solution depneds on WeakMap, which is supported on IE 11, Edge. Some older mobile browsers
* don't have support for it either. Check support for WeakMap.
*/
(function () {
//Make sure all objects and functions gets unique ids.
var uidMap = new WeakMap(); //WeakMap needed to not leak memory. Also avoids adding _uid to each object.
function getUID(obj) {
if (uidMap.has(obj)) {
return uidMap.get(obj);
} else {
var uid = 'xxxxxxxx'.replace(/x/g, replacer).toLowerCase();
uidMap.set(obj, uid);
return uid;
}
}
function replacer() {
return (Math.random() * 100 % 36 | 0).toString(36);
}
var bindMemory = {};
EventTarget.prototype.on = function (type, func, context, useCapture) {
if (arguments[2] === undefined || typeof arguments[2] === 'boolean') {
return this.addEventListener.apply(this, arguments);
} else {
var key = getUID(this) + '#' + type + '#' + getUID(func) + '#' + getUID(context)
+ '#' + (useCapture ? 'true' : 'false');
if (!bindMemory[key]) { //can't add two listeners with exact same arguments
var newFunc = func.bind(context);
bindMemory[key] = newFunc;
return this.addEventListener(type, newFunc, useCapture);
}
}
};
EventTarget.prototype.off = function (type, func, context, useCapture) {
if (arguments[2] === undefined || typeof arguments[2] === 'boolean') {
return this.removeEventListener.apply(this, arguments);
} else {
var key = getUID(this) + '#' + type + '#' + getUID(func) + '#' + getUID(context)
+ '#' + (useCapture ? 'true' : 'false'),
newFunc = bindMemory[key];
if (newFunc) {
delete bindMemory[key];
this.removeEventListener(type, newFunc, useCapture);
}
}
};
}());
</script>
<body>
<button id="btn">Click me</button>
<script>
var context = {
onClick: function () {
console.log('Check if this === context : ');
console.log(this === context);
btn.off('click', context.onClick, context);
}
},
btn = document.querySelector('#btn');
btn.on('click', context.onClick, context);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment