JavaScript: The Definitive Guide

Previous Chapter 9 Next
 

9. Further Topics in JavaScript

Contents:
Automatic Data Type Conversion
Explicit Data Type Conversions
By Value vs. By Reference

This chapter covers miscellaneous JavaScript topics that would have bogged down previous chapters had they been covered there. Now that you have read through the preceding chapters, and are experienced with the core JavaScript language, you are ready to tackle the more advanced and detailed concepts presented here. In fact, you may prefer to move on to other chapters and learn about the specifics of client-side JavaScript at this point. Do be sure to return to this chapter, however. You will not truly understand the workings of the JavaScript language if you have not read the material in this chapter.

9.1 Automatic Data Type Conversion

We've seen that JavaScript is an untyped language. This means, for example, that we don't have to specify the data type of variable when we declare it. The fact that JavaScript is untyped gives it the flexibility and simplicity that are desirable for a scripting language (although those features come at the expense of rigor, which is important for the longer, more complex programs often written in stricter languages like C and Java). Another feature of JavaScript's flexible treatment of data types is the automatic type conversions that it performs. For example, if you call document.write() to output the value of a Boolean value, JavaScript will automatically convert that value to the string "true" or the string "false". Similarly, if you write an if that tests a string value, JavaScript will automatically convert that string to a Boolean value--to false if the string is empty and to true otherwise.

The subsections below explain, in detail, all of the automatic data conversions performed by JavaScript.

Conversions to Strings

Of all the automatic data conversions performed by JavaScript, conversions to strings are probably the most common. Whenever a nonstring value is used in a "string context," JavaScript converts that value to a string. A "string context" is anywhere that a string value is expected. Generally, this means arguments to built-in JavaScript functions and methods. As described above, for example, if we pass a Boolean value to document.write(), it will be converted to a string before being output. Similarly, if we pass a number to this method, it will also be converted to a string before output.

Another common "string context" occurs with the + operator. When + is used with numeric operands, it adds them. When it is used with string operands, however, it concatenates them. When one operand is a string, and one is a nonstring, the nonstring operand will first be converted to a string and then the two strings will be concatenated:

x = 1 + 2;                // yields 3
x = 'hello' + 'world';    // yields 'helloworld'
x = 1 + '2';              // yields '12'
x = true + '3';           // yields 'true3'

Actually, the + operator even works when both operands are of object type: the operands are converted to strings and concatenated. When one operands is an object, and the other is neither an object nor a string, both operands are converted to strings and concatenated:

x = window + 1;             // yields '[object Window]1'
x = window + top;           // yields '[object Window][object Window]'
x = window + true;          // yields '[object Window]true'

The paragraphs above have described the "string contexts" in which values are converted to strings. Here is exactly how that conversion is performed:

Conversions to Numbers

Just as JavaScript values are automatically converted to strings when used in a "string context," they are automatically converted to numbers when used in a "numeric context." The two numeric contexts are:

For example, the following lines of code contain non-numeric values in numeric contexts, and cause automatic conversion to occur:

Math.sin("1.45");       // String "1.45" converted to number 1.45
done = sum > "10"       // String "10" converted to number 10
sum = sum + true;       // Boolean value true converted to number 1
total = total - "3";    // String "3" converted to number 3
Note, however, that the following line of code does not cause a numeric conversion to occur.

total = total + "3"
Recall that the + operator adds numbers and concatenates strings. Since there is one string operand in this example, JavaScript interprets the operator as the string concatenation operator, rather than the addition operator. Therefore, there is not a numeric context here, and the string is not converted to a number. In fact, just the opposite occurs: the numeric value total occurs in a string context, and therefore is converted to a string.

JavaScript values are converted to numbers according to the following rules:

Conversions to booleans

When a JavaScript value is used in a "boolean context", it is automatically converted to a boolean value. A "boolean context" is anywhere that a boolean value is expected: boolean arguments to certain built-in methods, the return value from certain event-handlers, and, more commonly, the expressions used by the if statement, the while and for loops, and the conditional (:?) operator.

For example, the following lines of code use the integer i, the string s, and the object o in boolean contexts, and cause those values to be converted to boolean values:

for(i = 10; i; i--) document.write(messages[i]); 
response = s?"yes":"no";
if (o) sum += o.value;

In C, there is no boolean type. Integer values are used instead, and just about any value can implicitly be used in a "boolean context". In Java, however, there is a boolean type, and the language does not permit any conversion, implicit or explicit, to boolean values. This means that you need to be very precise with your if and while statement (for example) in Java. JavaScript--like Java--has a boolean type, but--like C--it allows just about any type to be used in a boolean context. If you are a C programmer, you will find the JavaScript boolean conversions intuitive and convenient. The conversions follow these rules:

Conversions to Objects

Just as JavaScript values are converted to strings, numbers, and boolean values, when used in the appropriate context, so too are they converted to objects when used in an "object context." This is the most subtle of the automatic conversions, and it is possible to use JavaScript without ever realizing that it is happening. A value is used in an "object context" when you use the . operator to read or write a property of the value or to reference a method of the object. A value is also used in an object context when you use the [] operator to access an array element of the value.

Why would we want to do this? If a value is not already an object, how can it have properties or methods to access, anyway? Consider JavaScript strings, for example. JavaScript defines quite a few methods that can operate on strings. If s is a string, then each of the following lines is legal JavaScript:

len = s.length;
document.write(s.bold());
t = s.substring(2,4);
a = s.split(",");
A string isn't an object, so why can we treat it like one? Are strings simply a special case supported by JavaScript? Are they a special data type that is half object, half primitive type? No. When a JavaScript string is used in an object context, as the strings in the above example are, they are converted to a String object that represents the same underlying value as the original string did. (Note the capitalization convention: the primitive type is a string, the corresponding object is a String.) The String object defines a length property and quite a few methods that perform various operations on the string.

Strings are the primary example of why and when this sort of automatic conversion to an object data type is necessary. But it is occasionally used with other data types as well. For example, JavaScript will convert a function value to a Function object so that you can access the arguments property, which is an array of arguments passed to the function. Also, a numeric value can be converted to a Number object, which allows you to invoke the toString() method of that object, a method that takes an optional argument to specify what base the number should be converted to.

The rules for automatic conversions to objects are particularly straightforward:

The conversion of values to objects is handled quite transparently by JavaScript, and it is often not obvious to a casual programmer that the conversion is happening at all. This is for two reasons. First, the converted objects are transient: suppose a string, for example, is converted to a String object, and a method is invoked on that String object. The String object is never saved into a variable, and so it is used once and then is no longer available to the program (it is "garbage collected" so memory is not wasted). This makes it difficult to even obtain an instance of a String object. To do so, we must explicitly convert our string to String object. We can do this in either of two ways:

s = new String("hello");
s = new Object("hello");
Similarly, we can create Number, Boolean, and Function objects by invoking the Number(), Boolean(), or Function() constructors with our number, boolean, or function value, or, more generally, by invoking the Object() constructor with the value to be converted.

The second reason why conversion to objects is often transparent to programmers is that each of the String, Number, Boolean, and Function objects have toString() methods that are invoked when they are used in a string context, and have valueOf() methods that are invoked when they are used in numeric, boolean, or function contexts. Because the data conversion is so completely automatic, it can be difficult to even distinguish between a value and its corresponding object. The typeof operator provides one way to distinguish primitive values from objects. When invoked on a primitive value, typeof will return one of the strings "string", "number", "boolean", and "function". When invoked on the corresponding object, however, it will return "object":

typeof "hello"               // returns "string"
typeof new String("hello")   // returns "object"

Conversions to Functions

The only time that JavaScript can convert a value to a function is when a Function object is used in a function context (which occurs when you use the () operator to invoke a value.) In this case, the Function object is trivially converted to the primitive function value it represents. Using any value other than a function or a Function object in a function context will cause JavaScript to display an error message.

Data Conversion Summary

While many of the automatic data conversions explained in the subsections above are intuitive, there are so many of them that it can be difficult to keep them all straight. Table 9.1 summarizes each of the possible conversions.

Table 9.1: Automatic Data Type Conversions
  Used As:
Value: String Number Boolean Object Function

non-empty string

-

Numeric value of string, or error

true

String object

error

empty string

- 0 false

String object

error
0 "0" - false

Number object

error
NaN "NaN" - true

Number object

error
Infinity "Infinity" - true

Number object

error

Negative Infinity

"-Infinity" - true

Number object

error

any other number

string value of number

- true

Number object

error
true "true" 1 -

Boolean object

error
false "false" 0 -

Boolean object

error

object or array

toString() result, or object type

valueOf() result, or error

valueOf() result, or true

-

error (unless Function obj)

null "null" 0 false - error

undefined value

"undefined" error false error error
function

Complete function text

error true

Function object

-


Previous Home Next
Array Summary Book Index Explicit Data Type Conversions

HTML: The Definitive Guide CGI Programming JavaScript: The Definitive Guide Programming Perl WebMaster in a Nutshell