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:
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 publishing is mainstream these days, and it's certainly more efficient and eco-friendly than conventional distribution channels. Sometimes, though, it's a pleasure to sit down with a printed magazine, and many readers will never enjoy reading long items digitally. Magcloud is a self-publishing service which combines e-publishing with print-on-demand.
Despite the numerous benefits, there can be potential issues with the conversion of paper documents into electronic archives. When scanning paper pages into PDF, it's possible to end up with the odd- and even-numbered pages in separate PDF files. It can be very time-consuming to collate them manually, but there is an easier way. Sean Stewart explains.
BCL easyPDF SDK is a set of PDF Programming Libraries designed specifically to help Software Developers / Programmers build and deploy enterprise class PDF applications for corporate wide PDF...