document.getElementsByClassName Example
(function(childNodes){
/* Another (C) WebReflection Silly Idea */
// how to re-use them all, just an example
if(!document.getElementsByClassName)
document.getElementsByClassName = function getElementsByClassName(className){
for(var
re = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"),
ret = [], i = 0, l = 0, length = childNodes.length, node;
i < length; ++i
){
if((node = childNodes[i]).nodeType === 1 && re.test(node.className))
ret[l++] = node
;
};
return ret;
}
;
// let the magic happen
})(document.getElementsByTagName("*"));
What we have here?
- A trapped live object, probably used in 90% of selector libraries, but performed via scope resolution (the document) and a function execution (the getElementsByTagName method) over all nodes ("*")
- a theoretically zero performances impact to retrieve again every node, being live there is no need to refresh it, and being trapped run-time, it will contain few nodes during the first execution
- a single scope able to create N functions based on one of the most common created HTMLCollection
What do you think?
Nice approach. Cool way to write your for loop also.
ReplyDeleteI like the thought process here. Good idea.
ReplyDelete@fearphage thanks again for the nodeType suggestion (and the silly typo for the className) :D
ReplyDeleteCheers guys
Hey I don't understand the regex
ReplyDelete(?:\\s|^) doesn't that mean you're checking for character before the beg. of the line?
Any benchmarks yet?
ReplyDeleteSamer, that means look for a space or it starts with and look for a space after or it ends with.
ReplyDeleteThe question mark is to avoid RegExp result cache.
Aaraon, not yet, what I expect is better loop performances, what I need to test, is if a wrapped live collection, the biggest one, slows down somehow the angine a la DOMNodeInserted. I think no, but I am not sure yet.
Regards
OK, no slowdown at all, and actually no benefits as well. The problem is that I am basing my tests with wrong timers, so it's 0 or it's 15/16, I cannot truly understand if I it is worth it. In any case, as document.getElementsByClassName, it's really fast :D
ReplyDeleteCan you elaborate on the tests you're doing? I don't understand what you mean by "The problem is that I am basing my tests with wrong timers, so it's 0 or it's 15/16"
ReplyDeleteJ% I am taking the classic W3C page used in Taskspeed and others tests.
ReplyDeleteI put the function on the top, zero differences.
Then I perform a couple of searches, and I take time for each search.
Under windows, timers are almost useless, cause the result for a call that took 8 ms, for example, will always e 15 or 16, and never 8. This problem has been explained in John Resig blog few months (years?) ago :)
I like your approach very much, thanks for sharing :)
ReplyDeleteIt doesn't behave like a live collection... At least on IE8 SM. And it seems obvious to me, since ret is nothing more than an array.
ReplyDeleteAm I missing something?
If you want something like a static node list, you can check for querySelectorAll, which is provided by IE8 and should be a lot faster.
Massimo
you are missing the childNodes variables ... please read again, test, understand, and ask more if necessary. Regards
ReplyDeleteSorry to post again after 4 months...
ReplyDeleteYes, childNodes is indeed a live NodeList, but ret is just an Array. And we're just adding the matching elements to that array. So, the returned object is not a live list.
That's what I wanted to say.
IE8 still doesn't implement getElementsByClassName but implements querySelectorAll, so if you want to replicate getElementsByClassName you can use querySelectorAll instead, which return a non-live node collection.
I understand that's not the point of your idea, which is to create a scope where you can define every function you want that can make a good use of the live NodeList of all the elements.
So defining getElementsByClassName was just an example, I guess.