For a client's project, we needed to locate an HTML element with a particular class and scroll the containing division until that element was in view. Their page was large with a lot of tags (over 10,000 in part because tables were used for layout).

This is based on the getElementsByClassName Tips & Tricks article. Refer to that for details on how this works. Only the improvements are discussed here.

To improve the process, the function needed to limit the number of tags searched for the class name and be as efficent as possible. The number of tags searched is reduced by limiting the search to descendents of a specific element rather than the whole document and specifying the type of tag to look at rather than retrieving all tags. The code was made more efficient by replacing the for-loop with a while-loop.

Here is the code.

function cstmGetElementsByClassNameExt(parentElement, class_name, tag) {
    /* Extendeds function with performance improvements.
     * by using a parentElement and the tag the class is on
     * the list of elements to check is reduced.
     *
     * This function doesn't get bound to an object.
     */
    var docList;
    var matchArray;
    var re;
    var len;
    
    tag = tag || "*";
    parentElement = parentElement || document;
    if (typeof parentElement == "string") //object could be passed instead of Id
        parentElement = document.getElementById(parentElement);
        
    /* Get array of tags */
    if (tag == "*") {
       /* The test is to accommodate IE 5, 
        * leave it out if IE 5 support is not required 
        */
       docList = parentElement.all || parentElement.getElementsByTagName('*');
    } else {
       docList = parentElement.getElementsByTagName(tag);
    }

    /*Create a regular expression object for class*/
    re = new RegExp("(?:^|\\s)" + class_name + "(?:\\s|$)");

	/* Create output array*/
    matchArray = new Array();
    len = docList.length;
    
    /* Populate output array from tag array 
     * do loop is faster than for loop 
     * albeit out is in reverse order
     */
    while (len--) {
        if (re.test(docList[len].className)) {            
            matchArray[matchArray.length] = docList[len];
        }
    }
    //return matchArray.reverse(); //if the order needs to forward
    return matchArray;
}//eof

call:
var array = cstmGetElementsByClassNameExt("element-id","class-name", "tag2retrieve"); Or var element = document.getElementById("element-id"); var array = cstmGetElementsByClassNameExt(element,"class-name", "tag2retrieve");

This version works as a standard function and takes three parameters. See the version below for an object-oriented version.

Parent Element
The parent element is a tag on the page that contains the HTML element(s) with the class you're seeking. It can be an ID string or a reference to the HTML-object, the document, null or the empty string "" (quotes with no space)—the last two use the document. A string might be the more common type, but sometimes a calling function will have already created a reference so it will accept that. There is no benefit in converting the reference to the ID string and then back.
Class Name
The class name string being sought, it identifies the target HTML element(s).
Tag Name
An optional tag name to restrict the search to HTML elements of a particular tag—say input or p elements. If this value is not provided, all tags within the parent are searched. Providing this can speed up the process by reducing the number of elements returned by getElementsByTagName.

  While Loop

One notable difference from the basic version is the use of a while loop to step through the array returned by getElementsByTagName instead of a for loop. The while-loop is clean and compact. More importantly it is faster than the for-loop, and going in reverse order is again faster. One short coming, the last matches retrieved are first in the returned array. This usually won't matter, and the array method reverse can be used to quickly change the order.

On pages where a large number of elements are returned by getElementsByTagName and few have the required class, this technique can save significant processing time.

  A Method to Bind

This second version uses the key word this in place of the parentElement parameter, and must be used as a method of an object.

function cstmGetElementsByClassNameExt2(class_name, tag) {
    /* Bonus function with performance improvements
     * by using this for the parent element along with tag
     * to reduce the list of elements to check.
     */
    var re = new RegExp("(?:^|\\s)" + class_name + "(?:\\s|$)");
    var matchArray = [];
    var docList;
    var len;
    
    /* Get array of tags */
    tag = tag || "*";
    if (tag == "*")
        /* The test is to accommodate IE 5,
         * leave it out if IE 5 support is not required */
        docList = this.all || this.getElementsByTagName('*');
    else
        docList = this.getElementsByTagName(tag);
        
    /* Populate output array from tag array 
     * do loop is faster than for loop 
     * albeit out is in reverse order
     */
    len = docList.length;
    while (len--) {
        if (re.test(docList[len].className)) {            
            matchArray[matchArray.length] = docList[len];
        }
    }
    //return matchArray.reverse(); //if the order needs to forward
    return matchArray;
}//eof

call option 1
var htmlObj = document.getElementById("parentElement"); htmlObj.getElementsByClassName = cstmGetElementsByClassNameExt; htmlObj.getElementsByClassName("open-row"); or having used Techniques to Extending HTML Elements var htmlObj = document.getElementById("parentElement"); htmlObj.getElementsByClassName("open-row", "tr");
call option 2
var htmlObj = document.getElementById("parentElement"); cstmGetElementsByClassNameExt.call(htmlObj, "open-row", "tr");
call option 3
var htmlObj = document.getElementById("parentElement"); cstmGetElementsByClassNameExt.apply(htmlObj, ["open-row", "tr"]);

The first call option may seem like it has a little more code than a quick function needs. But, if you are going to make the called several times with the same parent this works well; it can be bound once and called as often as needed. The article, Extending HTML Element Constructors, shows how to extend HTML elements to include a user function as a method.

The second call option uses the Function method call where the first parameter is the object this will reference. The following arguments are the expected function parameters.

The third option is similar to the second. It uses the Function method apply, which is supported by older browsers. Instead of a comma delimited list of arguments, it takes an array of arguments. This is particularly handy if the parameters are already in an array.

Click on the button to find the elements that have a className of test1. The count and their IDs will be displayed. This paragraph is one (class test1) and its ID is dummy-paragraph.