PDF In-Depth

Testing for Object Types in JavaScript

February 01, 2001

Advertisement
Advertisement
 

The other day, I was writing a JavaScript function and came across an interesting problem: how to get the type of an object (Date, String, RegExp, Array, Number, etc.) programmatically. The situation is simple. Let's say you have a function that can take either an Array or a String as an argument. If the argument is an Array, you can (of course) invoke Array methods on it, but if the argument is a String, you'll get runtime errors if you try to invoke Array methods. So, how do you tell whether the function was passed an Array versus a String?

Languages like VBScript have an isArray() method, but JavaScript doesn't. JavaScript has a typeof operator. But typeof testing can be tricky. For example:

var abc = "ABC";var def = new String("DEF");var t1 = typeof abc; // t1 =  =      

'string'var t2 = typeof def; // t2 == 'object'

Type vs Object

You thought abc and def were both strings? Think again. Anything created by a constructor is (by definition) an object and will give a result of 'object' when tested by typeof. A string literal is a direct representation of the low-level 'string' data primitive in JavaScript. You can invoke String-object methods on variables of the 'string' type, but when you do that, what's happening behind the scenes is that the runtime interpreter is actually promoting the string literal to a String object (temporarily).

The long and short of it is that if you use the "typeof" test to test whether a string is a String, you'll get into trouble a good deal of the time. A String object is an object, not a string.

Confused yet? It gets worse.

(In case you haven't noticed, I capitalize String when I'm referring to the object form. Lowercase string refers to the data type.)

At this point you're probably thinking, okay... to distinguish a String from an Array, you can just invoke a String method and see if it works. If it works, the input was a String.

The problem is, if you invoke a non-existent method on an object, you get a runtime error. Try invoking charAt() on an Array object and you'll see what I mean. Not a good thing to do.

What about properties? Surely Array objects and String objects have different properties. Find one that is unique to Strings, say, and test its definedness with typeof. Right?

Wrong. Strings and Arrays have just one property, called length.

Stumped again.

The Solution

I looked online for other answers to the isArray() problem in JavaScript, figuring why should I reinvent the wheel if somebody else has sweated through it already. But I found only non-answers and incorrect answers.

Time to do a little hacking.

What I came up with relies on the fact that every object in JavaScript has a constructor function, which you can access explicitly by means of the constructor property. As an experiment, I suggest you try:

app.alert( (new Array).constructor );

Attach that code to a button in a PDF form and run it. You'll get a dialog that says

function Array() { [native code] }

The trick, then (are you thinking what I'm thinking?), perhaps, is to cast the object's constructor to a String and test the result for the presence of the substring 'Array' (if we're testing for arrayness). In other words:

// Return a boolean value telling whether // the first argument is an Array object. 

function isArray() {if (typeof arguments[0] == 'object') {  var 

criterion = 

    arguments[0].constructor.toString().match(/array/i); 
 return (criterion != null);  }return false;}

You can pass my version of isArray() any number of arguments, including none at all. If arguments were passed, we only care about the first (actually the zeroth) one. We test that one, which is to say arguments[0], to see if it is of type 'object'. If it is not, we return false. If the first passed-in argument is indeed an object, we need to check it to see if it harbors an Array. This is where the rubber meets the road. First, we grab the object's constructor. (Remember, every object has one.) We cast it to a string with toString(): an essential step. And finally, we look inside the resulting String to see if there is an occurrence of the word 'array' (in upper or lower case). The way the match() method works is that any successful match against the regular expression supplied as an argument will return an array, the zeroth element of which is the match text. On failure (no match), null is returned. Therefore, we must check the end result of this mess for non-nullness. And we return the corresponding boolean value.

isString()

A small change to the above code has to be made before it will work as a check of stringness. Can you see the problem? You can't just substitute a new regular expression at the end (/string/i in place of /array/i), because if you do, the code will return false if you do isString("abc").

Here is the properly modified code:

// Return a boolean value telling whether // the first argument is a string. 

function isString() {if (typeof arguments[0] == 'string') return true;if 

(typeof arguments[0] == 'object') {  var criterion =   

    arguments[0].constructor.toString().match(/string/i); 
 return (criterion != null);  }return false;}

The first line of the function checks to see if the argument is a string primitive (string literal). This is key, because not every String is a string. (See discussion further above.) Some strings are inside object wrappers!

Next time, maybe we'll talk about why I got wrapped up in all this arrayness and stringness stuff in the first place. It's all for a good cause. Trust me!

PDF In-Depth Free Product Trials Ubiquitous PDF

Debenu Quick PDF Library

Get products to market faster with this amazing PDF developer SDK. Over 900 functions and an equally...

Download free demo

Back to the past, 15 years ago! Open Publish 2002

Looking back to 2002, it's amazing how much of the prediction became a reality. Take a read and see what you think!

September 14, 2017
Platinum Sponsor





Search Planet PDF
more searching options...
Planet PDF Newsletter
Most Popular Articles
Featured Product

Debenu PDF Aerialist

The ultimate plug-in for Adobe Acrobat. Advanced splitting, merging, stamping, bookmarking, and link control. Take Acrobat to the next level.

Features

Adding a PDF Stamp Comment

OK, so you want to stamp your document. Maybe you need to give reviewers some advice about the document's status or sensitivity. This tip from author Ted Padova demonstrates how to add stamps with the Stamp Tool along with related comments.