Bad Object Detection

A common technique for writing cross-browser JavaScript code is to detect the features that you wish to use before you actually use them. Good object detection is done on a case-by-case basis, analyzing each feature as it’s encountered.

Some common examples of object detection:

// Is XPath querying available?
if ( document.evaluate ) {}
// Does the element have style information?
if ( element.style ) {}
// Can you get the computed style?
if ( document.defaultView && document.defaultView.getComputedStyle ) {}

All that these are doing is detecting if these particular properties are available before trying to use them. If you were inclined you could take these a step further and attempt to verify the types of the object properties as well (such as verifying that document.evaluate is a function).

Now one common problem – and one that’s as old as JavaScript itself – is to use object detection as a means of making sweeping generalizations concerning a set of features or an entire browser.

The classic bad one is:

// Are we in IE?
if ( document.all ) {}

The obvious problem, with the above, is that it is capable of returning ‘true’ in browsers that aren’t Internet Explorer (such as Opera). The difficulty arises when the developer assumes that an Internet Explorer-exclusive feature is available based upon the existence of that simple – and completely unrelated – property.

That takes into account the obvious ‘enemy’ – an unknown browser – however there’s a far bigger threat: Unintended consequences introduced by libraries or obscure fringe cases introduced by the user or markup. Let’s look at both.

Feature Introduction by Libraries

Libraries frequently introduce features that are missing from a particular browser. A common one, for example, is introducing document.getElementsByClassName for browsers that don’t have it. At the same time I’ve seen code like the following:

// Are we using Firefox 3?
if ( document.getElementsByClassName ) {}

Which is incredibly problematic. To start with: That feature may be introduced, right now, by a library or other snippet causing unintended consequences in your application. Additionally future browsers will inevitably introduce this feature (such as Safari 3.1) causing this detection to go completely out the window.

Fringe Cases From Global Variables

While they don’t happen often for those that they do happen to they can be a living hell. Specifically when object detection takes place within the global object (e.g. window.opera) then all bets are off as to its cross-browser applicability. Let’s take a look at an example:

<html>
<head>
<script>
window.onload = function(){
  if ( window.opera ) {
    alert("You're using Opera, pick me!");
  }
};
</script>
</head> 
<body>  
  <h1>Which browser?</h1>
  <a href="http://mozilla.com/" id="firefox"> Firefox</a><br/>
  <a href="http://apple.com/" id="safari"> Safari</a><br/>
  <a href="http://opera.com/" id="opera"> Opera</a><br/>
  <a href="http://microsoft.com/" id="ie"> Internet Explorer</a>
</body>
</html>

You would expect the alert to pop up when the user visits the page in Opera – and it does – however the alert also comes up in Internet Explorer. This is because all elements with an ID are automatically introduced as global variables (in the above there are four globals: firefox, safari, opera, and ie that all reference their associated elements). This is a fantastically difficult bug to spot and work around – thus you should be very cautious when doing any form of object detection on the global object.

Of course, it almost goes without saying, that there could exist an ‘opera’ variable elsewhere in the site that could interfere with this detection. Although that would, arguably, be easier to detect as it would make every browser trigger a false positive.

There’s two morals here:

  1. Only use object detection to detect exactly what you need to use.
  2. Be wary of detecting properties on the global object – it’s capable of lying to you.

Posted: February 29th, 2008


Subscribe for email updates

21 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

John Resig Twitter Updates

@jeresig / Mastodon

Infrequent, short, updates and links.