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.
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.
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:
function square(x) { return x*x; }
"function square(x) { return x*x; }"
Note that you can override the default toString() method for any object, thereby controlling exactly how the object is converted to a string.
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
total = total + "3"
JavaScript values are converted to numbers according to the following rules:
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:
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(",");
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");
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"
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.
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.
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 |
- |