home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


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:

  • Numbers are converted to strings in the obvious way: the resulting string contains the digits of the decimal representation of the number. The number 123.45, for example, is converted to the string "123.45".

  • The Boolean value true is converted to the string "true", and the value false is converted to the string "false".

  • In Navigator, functions are converted to strings which consist of the text of the function definition, including the complete body of the function. Thus, a function defined as follows:

    function square(x) { return x*x; }
    
    is converted to the string:

    "function square(x) {
        return x*x;
    }"
    
    The JavaScript code in the function body may be reformatted during this conversion--note the insertion of newlines in the example above. Similarly, any comments in the original function definition will not appear in the resulting string. An interesting feature of the string conversion of a function is that it is guaranteed to be perfectly legal JavaScript code, and is thus may be passed to the eval() method to be reinterpreted (perhaps in some new context). You should not rely on this, however, because Internet Explorer 3.0 does not include the body of a function when it converts it to a string, and this behavior is not likely to change in future versions.

  • Objects are converted to strings by calling their toString() method. By default, most objects have a toString() method that specifies at least the type of the object. For example, the Window object window is converted to the string "[object Window]". Similarly, the navigator object converts to the string "[object Navigator]". By default, all user-defined objects convert to the vague string "[object Object]".

    Note that you can override the default toString() method for any object, thereby controlling exactly how the object is converted to a string.

  • The null value is converted to the string "null", and the JavaScript undefined value is converted to the string "undefined".

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:

  • Numeric arguments to built-in functions and methods (arguments to user-defined functions do not have a type defined, so no conversion is performed).

  • Operands of various arithmetic, comparison, and other operators.

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:

  • If a string contains the decimal representation of an integer or floating-point number, with no trailing non-numeric characters, then the string is converted to that number. If the string does not represent a number, or contains trailing characters that are not part of the number, then the attempt to convert it fails, and JavaScript displays an error message. As a special case, the empty string ("") is converted to the number 0.

  • The Boolean value true is converted to the number 1, false to 0.

  • null is converted to the number 0.

  • Objects are converted to numbers by invoking their valueOf() method, if they have one. If the valueOf() method returns a number, that value is the result of the conversion. If valueOf() returns a string or Boolean value, then that value is converted to a number following the rules above. If the valueOf() method returns some other type, or if no such method exists, then the conversion fails, and JavaScript displays an error message.

  • Functions and the undefined value cannot be converted to numbers. Using a function or an undefined value in a numeric context will always cause a error message to be displayed.

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:

  • The number 0 is converted to false. All other numbers are converted to true.

  • The empty string ("") is converted to false. All other strings are converted to true.

  • null is converted to false. Non-null objects are converted to the value true, with one exception: if the object has a valueOf() method, and that method returns false, 0, or the empty string, then the object is converted to false.

  • Functions are always converted to the value true.

  • Undefined values are converted to false.

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:

  • Strings are converted to String objects.

  • Numbers are converted to Number objects.

  • Boolean values are converted to Boolean objects.

  • Functions are converted to Function objects.

  • null and the undefined value cannot be converted to objects, and cause an error message to be displayed if used in an object context.

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