This is the third part of a series “All about types” in Javascript.

Explicit type conversion

When I wrote about automatic type conversion I told my story of testing if “0” really converts to true, which I did by comparison to true. That was wrong, as I found out, but what is the right way? One possibility is

if ("0") { alert("true"); } else { alert("false"); }

which is ugly. Furthermore, this technique can only be used to convert values to boolean. How do I explicitly convert, for example, a boolean to a number?

There are two ways to do so. One is a more formal apporach, the other is somewhat hackish, though it is used commonly.

To every primitive type (string, number and boolean) there is a corresponding object constructor (String, Number and Boolean). If you call any of these as a function instead of a constructor, they perform type conversion. Thus, to do explicit type conversion, you do this:

Number("42"); // returns 42 String(42); // returns "42" Boolean(42); // returns true

The hackish way to do the same is this:

"42" - 0; // convert to number 42 + ""; // convert to string !!42; // convert to boolean

As stated in the first part, the minus operator – converts all operands to numbers, therefore by subtracting 0, the string “42” is converted to the number 42. Alternatively you could multiply “42” by 1.

If one operand is a string, the plus operator converts the other to a string as well. So by concatenating one value to the empty string, that value is converted to a string.

The logical not operator ! converts its operand to a boolean. Unfortunately to the opposite value. If “foo” converts to true, !”foo” converts to false. Well, to convert it to the matching value simply add another not operator. !!”foo” then converts to true. Hooray!

What’s the use of this hackish type conversion? We have a nice way to do type conversion by explicitly using Number, String and Boolean, this is highly comprehensible, why on earth would you prefer something like !!”42″ to Boolean(“42″)?

Speed, that is. I did some performance tests to proof that, and yes, !!”42” is faster than Boolean(42). About 17 times faster in Chrome 2, about 5 times faster in IE 6, about 8 times faster in Firefox 3 and so on. Conversion to number is 1.25 (Chrome) to 3.5 times faster (Firefox), to String is about 2.5 times faster in Firefox, but slightly slower in Opera.

But! Let me repeat the mantra of code optimization: “No premature optimization”. Again: “No premature optimization”! The speed advantage for a single conversion is between 0.000116 milliseconds (Chrome, to boolean) and 0.000962 milliseconds (IE 6, to string). Both is less than one microsecond. That’s imperceptible.

So what about parseInt?

So, if you should use Number to convert a value to a number, what’s the use of parseInt and parseFloat? Don’t they do the same?

No, they don’t, not exactly. Number accepts parameters, that are string representations of decimal, octal or hexadecimal numbers.

Number("12"); // decimal, 12 Number("0x12"); // hexadecimal, 18 Number("012"); // octal, 10

While this is true for parseInt as well, parseInt goes further. parseInt accepts parameters that start with a string representation of a number.

parseInt("314abc"); // 314 Number("314abc"); // NaN

Beyond that, there is a slight difference in handling octal numbers. If the given string starts with “0” (but not with “0x”), it is interpreted as an octal number, no matter what follows. Thus

parseInt("09"); // 0

Since “09” starts with a 0, an octal number is assumed. The next character, “9” is not a valid octal numeric character. Remember, parseInt accepts values that start with a string representation. Since “09” is not a valid octal number, the longest substring “0” is taken.

Number behaves differently. Since “09” is not a valid octal number, a decimal number is assumed, and thus the leading “0” is ignored.

Number("09"); // 9

This problem often occurs when parsing user data. Imagine the user enters a date as a string in the format “2009-06-09”.

var userString = "2009-06-09"; var dateParts = userString.split("-"); // ["2009", "06", "09"] var year = parseInt(dateParts[0]); // 2009 var month = parseInt(dateParts[1]); // 6 var day = parseInt(dateParts[2]); // 0, bang!

There are two ways to prevent errors like that. The first is to use Number instead:

var userString = "2009-06-09"; var dateParts = userString.split("-"); // ["2009", "06", "09"] var year = Number(dateParts[0]); // 2009 var month = Number(dateParts[1]); // 6 var day = Number(dateParts[2]); // 9, hurray!

The second is to explicitly denote a base:

var userString = "2009-06-09"; var dateParts = userString.split("-"); // ["2009", "06", "09"] var year = parseInt(dateParts[0], 10); // 2009 var month = parseInt(dateParts[1], 10); // 6 var day = parseInt(dateParts[2], 10); // 9, hurray!

Personally, I prefer the second way. By the way, parseInt is the fastest way in Chrome and Firefox 3 to convert a string to number, while it’s the slowest in all other browsers I tested.

Summary

To explicitly convert one value to a differnt type, use Boolean, String and Number. You might use parseInt instead for converting user input, to only accept decimal numbers.