Language Anomalies

Language Anomalies

Despite using a familiar syntax with keywords you probably recognize, there are a couple of things about JavaScript that can catch you by surprise. How objects are compared for equality is probably different than you expect. And the JavaScript language has the notion of objects being null or undefined. If you don’t recognize these unique characteristics of JavaScript, you can get yourself into trouble and spend a lot of time debugging to find the source of the problem.

What Is Equality?

If you are just getting started with JavaScript and coming from a compiled language like C# or VB.NET, be prepared for a whole new kind of debugging challenge! I first came to JavaScript from a “vanilla” C programming background and was surprised by how many of my programming mistakes the compiler was catching. Not only is JavaScript typeless; it also doesn’t use a compiler! The only way to detect syntax errors, even simple ones such as improper case, is to run the code. And you must exercise every possible code path just to do what a compiler would do for you. This is one example of the huge benefit you can get from using the Microsoft ASP.NET AJAX client script library: There’s a large amount of fully debugged code ready for you to use in your own applications!

As mentioned previously, JavaScript shares its treatment of Boolean values with the C language. JavaScript and C need a double equals sign for a logical test, and they use a single equals sign for an assignment. This can become painfully apparent when you find a missing equals sign in a comparison test. JavaScript programmers quickly find that assignment is not equality, except in the eyes of the script! In Listing 3-6 (from AssignmentIsTrue.aspx), I attempt to test the value of the year variable but mistakenly include only one equals sign instead of two. This means that I am actually assigning a new value to the variable, and the value of this assignment is nonzero, so when treated as a Boolean, the assignment evaluates to true.

Listing 3-6
Image from book

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Assignment Is True</title>
<script type="text/javascript">
var year = 1971;

if(year = 1968) {
  alert("this is true");
}
else {
  alert("this is false");
}
</script>

</head>
<body>
    <form id="form1" runat="server">
    <div>

    </div>
    </form>
</body>
</html>
Image from book

You might be telling yourself that this is a silly mistake that you aren’t likely to make. If you’re a C# programmer, you may be lulled into a false sense of security because the compiler catches these errors for you, but these kinds of errors are still common in the real world. In addition, there is more to this com-parison-testing subject in JavaScript. Even if you never accidentally use a single equals character instead of two, you might still not be safe from problems with equality checks. You may intend to test for equality, but JavaScript’s type coercion can still prove to be a problem. Consider the code in Listing 3-7 (Equality.aspx). The album variable is defined and then checked with the equality operator against null. It is true. The album variable has not been assigned yet and when evaluated against null is seen as equivalent. The next check shows that the variable is not true or false when checked explicitly. After that, the album variable is treated as a Boolean, and by definition a Boolean can’t be both not true and not false. It’s got to be one or the other, so it is coerced into one automatically, and JavaScript will treat it as false (the “!” not operator forces it to be treated as a Boolean even though we already determined that it’s not Boolean). Is your head starting to spin? Other types will be coerced automatically for comparison as well. The next equality check shows the string 5 being compared against the number 5 and evaluating to true. The number is coerced to a string for comparison purposes, similar to .ToString() in .NET. Boolean true and false values are treated as one and zero, respectively. Zero is false and nonzero is true. But the strings are not converted to equivalent Booleans, which hardly seems to make sense anymore. The last comparison shows that JavaScript also has the concept of variables being undefined. Because nothing has been assigned to album, its type is undefined.

Listing 3-7
Image from book

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Equality</title>
<script type="text/javascript">
var album;

if(album == null){
 alert("album is null");
}

if ((album != true) && (album != false)) {
 alert("album is not true or false");
}

if(!album) {
 alert("but !album is true");
}

if (5 == "5") {
 alert("number 5 equals string 5");
}

if ((0 == false) && (1 == true) && (!0) && (1)) {
 alert("0 is false and 1 is true");
}

if (('true' 
 alert("but 1 is not 
}

if ('undefined'
 alert("the album type is undefined");
}
</script>
</head>
<body>
    <form id="form1" runat="server">
    <div>    
    </div>
    </form>
</body>
</html>
Image from book

Null, Undefined, or Something Else

The subtle difference between something being undefined and null can easily turn into a problem in your code. One approach is to take advantage of JavaScript’s type coercion with a double negative. Instead of checking explicitly for undefined and null, you can apply the inverse operator twice: if (!!something). This approach can be extended to equality comparisons to avoid some of the confusion in the previous example. The string 5 is not really equivalent to the number 5 because the types are different, and in many cases you don’t want them to be treated as equal.

JavaScript originally had the equality and inequality operators that were in earlier examples. Later on, the strict equality and strict inequality operators were introduced. Instead of using two equal signs, you use three. This syntax results in a comparison performed without coercing types, so the types must be equal, and the values must be equal. In Listing 3-8 (from Inequality.aspx), I have duplicated the previous code listing but have changed to using the strict equality and inequality operators. The results are more intuitive and generally different from the previous set of comparisons. Notice that the undefined album variable is not strictly equivalent to null. It is actually 'undefined’, which means it doesn’t have a current type. And while it is undefined, it is neither true nor false as it was before with the standard equality operators. The number 5 is no longer considered equivalent to the string. And 0 and 1 are not really the same as true and false. Null is a value, not a type, and if you assign a null to a variable, it will take on the object type, which is not the same as having a type of undefined.

Listing 3-8
Image from book

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Inequality</title>
<script type="text/javascript ">
var album;

if(album !== null){
    alert ("album  is not null");
}

if ('undefined' ===
    alert("the album type is undefined");
}

if ((album !== true) && (album !== false)) {
    alert("album is not true or false");
}

if (5 !== "5") {
    alert("the number 5 is not equal to the string");
}

if ((0 !== false) && (1 !== true)) {
    alert("false is not 0 and true is not 1");
}
</script>
</head>

<body>
    <form id="form1" runat="server">
    <div>

    </div>
    </form>
</body>
</html>
Image from book

I recommend using the strict equality operators as your default for performing comparisons. You should only use the original equality comparisons when you specifically want the types to be coerced as part of the comparison. This will save you hours of frustration in the long run.