JavaScript on the one hand is very good for the beginning programmer because it is very forgiving in regard to variable types. Other languages require that you define the type of a variable at the outset and only ever store the correct kind of data in it. JavaScript doesn't actually care and modifies the type of a variable on the fly according to the values being presented.
Type conversion happens automatically as needed. To support this, a set of polymorphic operators are provided to make the conversion.
The following internal operators are provided:
ToPrimitive
ToBoolean
ToNumber
ToInteger
ToInt32
ToUint32
ToUint16
ToString
ToObject
From the script writers point of view, these functions are inaccessible. However, you can call the constructors to invoke these functions indirectly.
The items of data themselves are still strongly typed, but the variable containers are smart enough to cope. There are some subtle rules to this however and you can create some situations where a very hard to diagnose problem occurs that is based on data typing inside the variables.
Type conversion happens during expression evaluation. You can still get rounding errors with Unary operators but you only need to worry about converting a single type.
If you think there is some ambiguity in your expression, you should force a conversion to the most appropriate type. Generally, object values should be converted to Numbers or Strings. Objects will generally have a preferred type that they yield when converted. In most cases that will be a number although Date objects prefer to become Strings.
Binary operators require two values and some require that both are of the same type or can be converted to the same type. If the type of the two operands is different, then you can have problems with some operators in expressions. If both need to be numeric for example, and once is not a legal numeric value even after conversion, then an error will result. The arithmetic and bitwise operators fall into that category.
The rest of the binary operators are polymorphic. That means they can cope with values of different types. The assignment operators will change the LValue to whatever type the RValue is. There is still some requirement here that the LValue is legally convertible. The comma operator doesn't combine its two operands in any way whatsoever.
Occasionally the interpreter may generate an error message due to its inability to legally convert a value to an appropriate type to complete the expression evaluation.
The relational operators cause some confusion since the values need to be converted for comparison but the relational comparisons work for several types. It is difficult to know what type will be used for the relational test unless you explicitly force a type conversion yourself.
The concatenation operator is also ambiguous because you may have two numeric strings and want to add them but the concatenate operator may join them together to make a string composed of both.
The addition/concatenation operator looks at the arguments and if either is a String already or preferentially converts to one, then a concatenation occurs. If neither operator prefers to be a String then a Number conversion happens and the values are added.
Relational operators perform the same deductive test. However, the conversion to Strings is less likely since relational operators are concerned with magnitude. However, they will test for collation order if both arguments are Strings.
Relational operators will attempt to convert both arguments to a Number and if they cannot, then they will use a String-based compare. If at least one argument can be converted to a Number then the other will be forced to be a Number for comparison purposes. So for a relation test to be String based, both arguments must be Strings, or string-like objects.
Tests for equality require further deductive reasoning on the part of the interpreter. The values are converted to their preferred types. If the types are the same then the values can be compared easily either as Numbers or Strings. If the types are different, then further conversion is necessary before the comparison can be completed. In that case, Boolean values become Numbers as do any other non-Numeric values and Numeric comparison predominates.
Comparing null with undefined values does not require any conversion and they will compare equal.
The ECMAScript compliant interpreters are based on comparison rules that prevailed prior to ECMAScript being formalized. However, JavaScript version 1.2 incorrectly anticipated that the standard would rule that equality required the type of the two operators to be identical. This means that a number in quotes will not test equal to the numeric value itself. Therefore "10" != 10 yields a true value instead of a false value. This will only come into play if you specify JavaScript version 1.2 in the language attribute of the <SCRIPT> tag in your web page. Placing a <SCRIPT LANGUAGE=JavaScript"> tag is sufficient to work around this. In Netscape version 4.0, if you don't explicitly ask for version 1.2 of JavaScript, you still have access to the JavaScript version 1.2 capabilities of the language except that this particular comparison works as per the pre-JavaScript version 1.2 rules. That is to say, it works correctly.
Version 6 of Netscape and version 5 of MSIE claim to be ECMAScript compliant and this problem should go away. Other browsers strive for ECMA compliance too, so as long as you avoid specifying JavaScript version 1.2 in your <SCRIPT> tags, you shouldn't encounter this problem.
New operators === and !== are introduced with the ECMA standard at edition 3 to provide a test that takes account of data typing. MSIE version 4.0 already supports them in anticipation of the third edition of the standard. Netscape supports them at version 6.0.
Earlier versions of MSIE and Netscape exhibited bugs in the comparison logic where the results of comparisons involving NaN, null and 0 where type conversions led to inconsistent behavior.
// String object scanned from numeric literal a = String(50); // Equivalent to "50" // Number object scanned from string literal b = Number("22.22"); // Equivalent to 22.22 // String literal coerced to numeric c = +("0x00FF"); // Equivalent to 255 // String with number subtracted d = "22.22" - 11.11; // Equivalent to 11.11 // Logical operator on string and number e = ("abcde" && 23); // Equivalent to 23 // Bitwise operator on string and number f = ("0xF0" & 255); // Equivalent to 240 // Number coerced to string by concatenation g = "100" + 10; // Equivalent to "10010" // Test for equallity of value h = ("100.1" == 100.1); // Equivalent to true // Test for identity of instantiation i = ("100.1" === 100.1); // Equivalent to false // Object coerced to string forcing number to be concatenated j = (new Object) + 10; // Equivalent to "[object Object]10"
ECMA 262 edition 2 - section - 9
ECMA 262 edition 3 - section - 9
Wrox Instant JavaScript - page - 35
Wrox Instant JavaScript - page - 37
Prev | Home | Next |
Type | Up | TypeError object |
JavaScript Programmer's Reference, Cliff Wootton Wrox Press (www.wrox.com) Join the Wrox JavaScript forum at p2p.wrox.com Please report problems to support@wrox.com © 2001 Wrox Press. All Rights Reserved. Terms and conditions. |