Over a million developers have joined DZone.

Bad Object Detection

DZone's Guide to

Bad Object Detection

· Web Dev Zone
Free Resource

Tips, tricks and tools for creating your own data-driven app, brought to you in partnership with Qlik.

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:

window.onload = function(){
  if ( window.opera ) {
    alert("You're using Opera, pick me!");
  <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>

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.

Explore data-driven apps with less coding and query writing, brought to you in partnership with Qlik.


Published at DZone with permission of John Resig. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}