Last active
March 5, 2016 17:13
-
-
Save Munawwar/ea0551bb4d3cdaf4ce42 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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