It's so you can do stuff like this.
At that point, why not just NOT make it anonymous... are you doing this to avoid polluting the global scope? There are usually sufficient other ways of handling that (like wrapping everything in a self instancing function, which I'm usually doing anyways) I'm not sure why I'd bother.
Again I think your cryptic/nonsensical method names aren't helping matters. When I think "on" or "off" I don't think adding or removing event handlers. You're not saying what any of these actually do in the function name, and that's increasing the difficulty of figuring out what any of your code does without any realistic benefit in return.
Kind of like arrow functions. I'm not a fan as they seem pointless to me in most usage scenarios whilst compromising code legibility. Your usage scenario above being a perfect example of what I mean; oh noes you might have to type the word "function". NOT that I'm even able to use them yet on most of my projects since I still deploy for the web at large.
Seriously, if this:
() => {
Is somehow magically superior in anyone's mind to this:
function() {
Well... I lack the words in polite company.
But then, I learned high level programming 38 years ago in Pascal and worship at the throne of all things Wirth. To that end even C syntax pisses me off as being needlessly, pointlessly, and aggravatingly cryptic. Hence why I'm STILL not convinced this is a joke:
gnu.org/fun/jokes/unix-hoax.html
... and for all the talk of JavaScript being a different language, to me it's still just C tarted up like a drag queen with theatrical makeup. stiletto heels, and a frilly dress.
Basically in that case, I think you're wasting time replicating existing behavior.
(function() {
function mdh1(e) {
e.currentTarget.style.color = '#FF0000';
}
zam.on('mousedown', 'h1', mdh1);
setTimeout(function() {
zam.off('mousedown', 'h1', mdh1);
}, 5000);
})();
Again NOT that I'd be using an element's style.
Also note I'd be hitting currentTarget and not target just in case a child element (like an anchor or span) is the trigger. Remember an Event's "target" isn't always the element you hooked the event handler to! That's why my polyfill for event handling in legacy IE creates an object as a wrapping handler to preserve the passed element since there is no equivalent to currentTarget.
Looking at the website, I cannot figure out what it does, find actual code examples, the documentation seems nonexistent, and overall the lack of content on the site (much less zero content per page) really isn't blowing my skirt up.
What little code I can find -- like that codepen -- seems to use outdated/sloppy methodology like writing markup to the document innerHTML style, use gibberish heading depths indicating a lack of the fundamentals of using HTML properly... and I think whatever it is doing is utterly banjaxed given how painfully slow loading even the pen is, much less the massive 5 second-plus delay for the event handler!
That you have to "new" the object instance also seems a bit wasteful/pointless.
Document it better, put more emphasis on working with the DOM instead of slopping out markup in strings, maybe provide some polyfills so it can actually be deployed on production websites... and maybe we'll talk.
You could probably also benefit from the fact that Object.prototype can be used to extend an existing object letting you {} your subfunctions instead of doing Zam.prototype.whatever every joe-blasted time. Same goes for your multiple VAR for nothing, checks for null on things that would never be anything but loose true or null, and so forth.
Even just something as simple as your (confusingly named) index function could be gutted down to:
Zam.prototype.countMatchingPrevSiblingTagNames = function(e) { var i = 0, match = e.tagName.toLowerCase(); while (e = e.previousElementSibling) if (e.tagName.toLowerCase() === match) i++; return i; }That way you aren't wasting time creating an extra element value, a calculation/function call that does NOT change in value isn't wasting time being run inside the loop, and you REALLY don't need to waste time on that null check since DOM nodes either exist or they don't.
THOUGH I would write that as:
Zam.prototype.countMatchingPrevSiblingTagNames = function(e) { var i = 0, match = e.tagName.toLowerCase(); while (e = e.previousSibling) if (e.nodeType == 1 && e.tagName.toLowerCase() === match) i++; return i; }Since previousElementSibling is too new to rely upon in deployment on websites -- though if all I cared about was building crapplets in something like electron, nw.js or so forth, THEN I'd skip the compatibility check.
NOT that I can figure out any reason why you'd want to count the number of matching tags that are previous siblings in a practical usage scenario.
Other functions could benefit from the "it's either null or loose true" optimization, take your (uselessly vaguely named) "c" function.
Zam.prototype.c = function(event, target, func) { if(typeof(func) === 'string') func = this.functions[func]; if (func.name !== 'anonymous') this.functions[func.name] = func; if (typeof(target) == 'object') e.addEventListener(event, func, false); else { target = document.querySelectorAll(target); for (var i = 0, e; e = target[i]; i++) e.addEventListener(event, func, false); } }NOT that I'm sure why you're wasting time storing the functions being assigned in an array.
Oh, and I'd probably skip the on/off functions, and instead of trying to pass an space delimited string to it, why not accept either a string or an array. String for single event, array for multiples. That would simplify the detection of what's being passed down to typeof, and speed things up since you wouldn't be wasting time (and possibly memory) on a String.splice. Likewise that recursive call is no winner.
I'd also kill the fadein/fadeout nonsense that should be handled almost entirely by the stylesheet and triggered by nothing more than a class swap/toggle. This plays to the notion that 99% of the time you access style="" from the JavaScript, you're probably doing something WRONG! Like creating/accessing styles that make no sense for non-screen media users.
But really a number of things it does -- like your entire Zam.html function -- are things I would NEVER do in modern JavaScript in the first place, and was never a fan of either. Use the bloody DOM so you can skip the entire parser stage in the browser saving time, RAM, and possibly battery life.
Hence why where you have this in your codepen example:
zam.html('.stats', ` <span> IP: `+data.ip+` City: `+data.city+` Zip: `+data.zip_code+` </span>` );My own elementals.js library would have this:
_.make('span', { content : '/\ IP: ' + data.ip + '\ City: ' + data.city + '\ Zip: ' + data.zip_code + \ \u00A0\ ', parent : document.getElementsByTagName(':span')[0] });(in practice I'd have to do a node flush, though depending on what the parent is I'd consider a 1:1 node replace skipping the SPAN entirely)
Note I'm using escaped line endings for multiline as backtick strings are too new for web deployment, and I have to use the utf-8 character code for a non-breaking space since my library uses document.createTextNode which escapes ALL code.
Which is an advantage to the approach of going to the DOM and building proper textnodes as it means code injections are impossible. The way you're doing it someone types in "<script>document.write('tarfu');</script>" as their city, and that scripting will actually RUN!
Hence why I think innerHTML really needs to go the way of the dodo for all but the rarest of corner-cases. It is an outdated, outmoded relic of the past that's saddled with gross inefficiencies.