I have got a JSP page which after being rendered needs to call an onload event to look for all divs (believe me there are many of them) having some style class assigned to them and hide them from view. This is one of those kitchen sink problem that came back to haunt me making me realize that JS DOM API doesn’t give me anything to fetch elements containing a class as one of its style attributes.
I came across one of the implementation which goes like this:
<script type="text/javascript">
function findByTagAndClass(tagName,cn1){
var list = document.getElementsByTagName(tagName);
var list2 = new Array();
for(var i in list){
if(hasClass(list[i],cn1)){
list2.push(list[i]);
}
}
return list2;
}
function hasClass(element,c){
if(element!=null && element.className!=null) {
if(element.className==c)return true;
var classes = element.className.split(" ");
for(var i in classes){
if(classes[i]==c)return true;
}
}
return false;
}
var list = findByTagAndClass('DIV','xyzClass');
</script>
With due credit to this piece for its correctness, one must not overlook the hasClass() which does a costly action of splitting the className string into Array to traverse over it and find the match. Just imagine numerous of unrelated divs goings across this cycle makes it a lesser meaningful approach. For those statistically inclined, the action, that has inspired me to write this entry, takes around 48 sec (on average) to render the page on IE 6. This example may as well qualifies for an Anti Pattern in JavaScript.
Here goes the two approaches I followed to tackle this issue.
- Minimize the scope of my search for the nodes with this class. Rather than searching over the whole document, its always better to find out if there exists an immediate parent node which contains all possible elements.
- Get rid of that splitting of
classNameto look for a matching type.
These will be taken care of as follows: (courtesy: AnyExample.com)
<script type="text/javascript">
function getElementsByClassName(searchClass, domNode, tagName) {
if (domNode == null) domNode = document;
if (tagName == null) tagName = '*';
var el = new Array();
var tags = domNode.getElementsByTagName(tagName);
var tcl = " "+searchClass+" ";
for(i=0,j=0; i<tags.length; i++) {
var test = " " + tags[i].className + " ";
if (test.indexOf(tcl) != -1)
el[j++] = tags[i];
}
return el;
}
var list = getElementsByClass(document.getElementById('div_mainTable'), 'DIV', 'xyzClass');
</script>
Notice that String.indexOf() turns out to be better and usually lighter approach. As much as this snippet helped me reduce the cost down to 20 sec (on average), I couldn’t stop myself to better this milestone. Understandably, using a regex to find a match is the next level, but why not reuse something already in place.
If Joshua Bloch (Author: Effective Java) says Know and Use the Libraries (Item 47), the scope of his teachings were never limited to Java. jQuery has redefined the way we can now traverse html document elements faster and with lesser effort in semantics of the algorithm.
All that talk and a better handling of boundary conditions (which will be unknown to us most of the time), can now be replaced by just one liner (modified after one of the comments suggesting a better way).
$("#div_mainTable div.xyzClass").hide();
Luckily I could find myself a method to hide the concerned components. Had this been not the case, I already had a way out:
$("#div_mainTable div.xyzClass").css({display:"none"});
For those beginners like me, the above piece of line is a chained query which first fetches all the children of element (id: mainDiv), filter out those of “div” tag followed by those which do not match the expression xyzClass before working upon them. Using the library did redefine the standard and cost went further down to 12 sec (on average).
For the completeness of the article, here’s how getElementsByClass can be agnostically implemented:
<script type="text/javascript">
function getElementsByClassName(searchClass, tagName, domNodeId) {
if(searchClass == null || searchClass == "")
return new Array();
else {
var expr = "";
if (domNodeId != null) expr = "#"+domNodeId+" ";
if (tagName != null) expr += tagName;
expr += "."+searchClass;
return $(expr).map(function(){
return $(this)[0];
}).get();
}
}
</script>
jQuery is en route a good web development framework featuring DOM elements selection, traversal and modification plus many more. Its unique chaining model we witnessed in the example to perform multiple operations on elements (in page document) deserve no less praise. I shall be coming up with more related & performance-oriented examples using this library to replace many day-to-day web development.

Hmm why not….
window.onload = function(){
document.body.className = 'jsenabled';
}
and in your CSS:
body.jsenabled .triggerClass {
position:absolute;
left:-4000px;
/* or any other – screenreader friendly hiding method */
}
You will never be as fast as the CSS parser.
Furthermore, if you write a getElementsByClassName these days, check that it doesn’t exist natively, as a lot of browsers support this now.
How about:
$("#mainDiv div.xyzClass").hide();jQuery accepts any css selector as it’s argument. No need to filter. And it has a built in method for hiding elements.
George, under the hood this is still a loop (or on Firefox one native call and then a loop).
document.evaluate is way faster..
see
http://mykenta.blogspot.com/2007/10/getelementbyclass-revisited.html
or
http://www.devpro.it/code/133.html
for a crosslibrary function.
@Chris
I didn’t mentioned it uprightly, though I did took the worst case scenario and built my write up over it to talk abt doing it using css selectors (given by jquery). I should elaborate more on how jquery is doing it by as well falling back on xpath (to use document.evaluate) or regex match.
Your approach of css selectors looks a better one, only if it works for me. Nevertheless it comes with its own tradeoff. What if I need to arrive to a class name only thru some conditional checks. Then I may again end up adding class to elements (by iterating)
The reason for providing the implementation suggests that this is not a native method but one can add to the DOM.
Prototype does that as well, but thats been deprecated.
Safari 3.1 has a native support for this method, suit follwed by FF3 n Opera 9.5, but can’t say how quickly we move our apps to these new versions? IE is still far from it.
@George
The optimization looks good. It works.
@kentaromiura
As for document.evaluate, does IE support it? FF2, FF3 & Opera 9.27 does, not sure of other versions.
If you look at my implementation i check if the browser support evaluate, otherwise it will fallback to the standard way of doing this using a standard way of iterating throught the dom,
i think jquery will use a simil approach under the hood, what it make a doubt in your method is that you’re chaining togever quite lot of methods.
I see lots of map and filter, and everyone of this method iterate a collection.
you are right…plz see George comments for a better impl. I was not aware of jquery accepting css selector arguments.
jQuery Cheat Sheet
http://www.cheat-sheets.org/saved-copy/Jquery-Cheat-Sheet-1.2.pdf