Today’s Techy Treasure is another basic staple for me, something simple, but which I use in virtually every script I write. It’s a method for retrieving element references — either single elements, or collections of elements referenced by tag name, and optionally filtered by attribute match.

Most JavaScript libraries have a function like this, often calling it $ (dollar). And while all of them work slightly differently, they all do basically the same thing. So if you’re new to JavaScript, and been wondering what’s inside those ubiquitous dollar functions, here’s a bit of anatomy for you!

As with all the methods I’ve written about in this column, I’m demonstrating it here as a global function, to make the examples more straightforward; but in practise you’d do better to define it as a method of a custom object:

function get(find, context, conditions)
{
	if(find.indexOf('#') != -1)
	{
		return document.getElementById(find.split('#')[1]);
	}

	else 
	{
		if(typeof context == 'undefined') 
		{ 
			context = document; 
		}
		
		var nodes = [], tmp = context.getElementsByTagName(find);
		for(var i=0; i<tmp.length; i++)
		{
			nodes.push(tmp[i]);
		}
		
		if(typeof conditions == 'undefined')
		{
			return nodes;
		}
		
		var filtered = [];
		for(i=0; i<nodes.length; i++)
		{
			var add = true;
			for(var c in conditions)
			{
				if(!conditions.hasOwnProperty(c)) { continue; }
				
				var attr = c == 'class' 
					? nodes[i].className : nodes[i].getAttribute(c);
					
				if(attr == null 
					|| attr == '' 
					|| new RegExp('(' + conditions

+ ')', '').test(attr) == false)
{
add = false;
}
}
if(add == true)
{
filtered.push(nodes[i]);
}
}
return filtered;
}
}

The get() method does three things. Firstly, it can retrieve a single element, a shorthand for getElementById:

var content = get('#content');

Secondly, it can retrieve a collection of elements, a shorthand for getElementsByTagName:

var paragraphs = get('p');

But thirdly, and most interestingly I think, it can filter a collection of elements according to attribute matches. What this feature amounts to is a getElementsByAttributeMatch() method, where multiple attributes can be matched in a single expression:

var codeblocks = get('code', document, { 
	'class':'javascript' 
	});

This third example is retrieving a collection of <code> elements which have the class name “javascript”; or to be more precise, elements where the value of the class attribute contains the string “javascript”.

In fact the value parameter of each key/value pair is evaluated as a regular expression, so you could do things like this:

var codeblocks = get('code', document, { 
	'class':'j(ava)?script|php' 
	});

You’ll notice in those examples that there’s a second argument before the condition object, which defines the context of the search. You can pass in a different document reference to retrieve a collection in that context (such as a page inside an iframe), or you can pass in an element reference to retrieve a collection of child elements within a specific element (such all list-items within a list).

Finally, what this method returns also depends on what you ask it for. For a single element it will return either that element or null; for a collection of elements (whether filtered by attribute conditions or not) it will return an array of elements (a true JavaScript array, not a DOM collection), and if no matching elements were found this array will be empty.

James is a freelance web developer based in the UK, specialising in JavaScript application development and building accessible websites. With more than a decade's professional experience, he is a published author, a frequent blogger and speaker, and an outspoken advocate of standards-based development.

Free Guide:

How to Choose the Right Charting Library for Your Application

How do you make sure that the charting library you choose has everything you need? Sign up to receive this detailed guide from FusionCharts, which explores all the factors you need to consider before making the decision.


  • Lachlan

    John Resig’s Sizzle library is excellent for this, lean, fast and very readable code.

    http://github.com/jeresig/sizzle/tree/master/sizzle.js

  • Jeremy

    Lachlan hit the nail on the head; why would anyone want to use this wannabe-library with a single “get” function when every major library has a much better implementation of $ (not to mention that those libraries also have a ton of useful functions BESIDES $). However, I disagree with Lachlan on using Sizzle directly; it may be appealing because it is used by several major libraries, but the VAST majority of developers would be better of using a library that implements Sizzle rather than using Sizzle itself.

  • Lachlan

    I actually was recommending the library as a way to learn how it works (which was the point of the post), it’s very well written code.

  • http://www.brothercake.com/ brothercake

    If you’re not interested in learning, Jeremy, that’s your choice. But please don’t waste other people’s time with your dismissive comments.

  • kangax

    Interesting snippet.

    A couple of notes:
    1) The scripts doesn’t take care of some attributes conversion (it only takes care of “class” -> “className” conversion but not, say, “for” -> “htmlFor”)

    2) When creating regexp, it’s a good idea to escape meta characters, since trying to match something like “?” will throw SyntaxError. I would just treat strings as strings and allow regexp objects as values.

  • SalvatoreC

    Thanks for being so kind and writing and publishing this code!

    I recently wrote something similar but not as complex, and feel very gratefull to see someone who knows more about Javascript than I demonstrate something similar.

    Lately I’ve been thinking I’m not writing enough code to learn how JavaScript really works without even considering cross-browser issues. I must write more code! I’m looking at too much code and not writing enough examples.

    Thanks again!
    I’m learning a lot!

Learn JavaScript for free!
Free course: Introduction to JavaScript

Yours when you take up a free 14-day SitePoint Premium trial.