JavaScript for the C# Developer Part 4 – JavaScript’s Dangerous and Wild Type System

In the previous posts about variables and functions I wrote extensively about how to manage scope and protect your variables from colliding with other scripts. The ease with which you can accidently create or affect global variables is one way JavaScript is like a long sharp piece of metal to be handled with care. This is especially important given JavaScript’s beautiful type system.


Types of types

Whenever I write anything based on presentations I go back and re-research the things I say in the talk. I do this because I might have been wrong about something I said and I can’t deny anything I put down in writing. The original slide deck for this series has a slide titled Primitive Types. When I began outlining this post I went out and tried to find an authoritative source to confirm what that slide says only to discover several sources that showed my slide to be slightly wrong! The problem was that these sources disagreed with each other!

Here is an article from MSDN, one from the Mozilla Developer Network, and one from Wikipedia. Each describe the subject of JavaScript types a bit differently and if you do the same research I did you will find many others. Finally I fell back on the ECMAScript JavaScript Language Specification which says that the primitive types are:

  • Undefined
  • Null
  • Boolean
  • String
  • Number
  • Object

That list is very interesting because as you saw in the previous post the result of typeof() for a function is ‘function’ (even though a function is really an object):


Just as interestingly, the typeof(null) is ‘object’ (even though null is really a Null):


Both of these results are proper and correct according to the spec for typeof in ECMAScript JavaScript Language Specification!

It’s important to understand that there is no such thing as an official JavaScript implementation. Just as with HTML and CSS, there is a specification and many individual implementations from different vendors. Furthermore, some of these implementations are quite old and have interesting quirks that are preserved for backwards compatibility. I have read that the behavior of typeof with regards to null is a manifestation of this.

Therefore, it seems that if I try to apply rigor to my discussion of the type system I will go down the rabbit hole into wonderland and focus on minute details and that is not the goal of these posts! For the purpose of this discussion I’m going to be a little lazy and simply focus on the types as described by the possible return values of typeof.

  • undefined
  • object
  • boolean
  • number
  • string
  • object
  • function

Undefined

When you declare a variable in C# you specify its type either explicitly via the declaration or implicitly using the var keyword based on the return type of an expression. In JavaScript a variable’s type is determined by its value. Furthermore a JavaScript variable’s type can change by assigning a value of a different type. Consider the following example (http://jsfiddle.net/DougWare/KrDtv/).


The typeof statement returns a string value with the name of the type. JavaScript also includes the named constant
undefined of type
undefined whose value is undefined. This is illustrated by the following boolean expression (http://jsfiddle.net/DougWare/NAGAr/).


You can test for the value undefined in a function with arguments to determine if the caller supplied an argument (http://jsfiddle.net/DougWare/MXaWB/).


The test for undefined in this example is safe because the existence of a variable named arg within the function’s scope is certain. However, in cases where the existence of a variable with a given name is not guaranteed you should always use typeof (http://jsfiddle.net/DougWare/2D3ds/).


If you test an undeclared variable for any value including undefined a runtime error is the result!

Null

JavaScript provides a named constant
null of type
object whose value is null. Null means that a variable exists, but that its value is unknown. There is a very subtle difference between a variable whose value is unknown and a variable whose value is undefined, but the former acknowledges that there is a value that is unknown whereas the latter just says a value was not supplied. Improper use of null is one of the hallmarks of a C# developer who is hacking together some JavaScript code. It is possible to rewrite a previous example and test for the presence of an argument by testing for null (http://jsfiddle.net/DougWare/wZVLD/).


This code looks correct and it works as intended, but it has two things wrong with it. The first is that it implies arg has some unknown value. The second is that it relies on the second biggest mistake C# developers make when they write JavaScript (after the accidental creation of global variables) – reliance on type coercion.

The Perils of Type Coercion, == Versus ===

Unless you already understood the reason, you were probably wondering why the examples of undefined used === but the example of null used ==. The answer is that === evaluates both the value and the type and is called the identity operator, but ==, the equality operator, attempts to coerce the types before the comparison. Consider this example (http://jsfiddle.net/DougWare/NPre7/).


This example should make it pretty clear how dangerous it is to rely on implicit type coercion. Furthermore, the math example might give you different results depending on the particular JavaScript engine that executes the code. Because the * operator only does multiplication, the runtime coerces x to a number and returns 25. However, the + operator does addition as well as string concatenation and in this case the runtime coerces y to a string and returns 55.

Many of the ‘JavaScript WTF?!’ examples I have seen rely on some sort of type coercion to achieve crazy results, but many examples like the test for null are relatively benign. That said, I always look for and flag == when I review JavaScript code.

Coercion in Boolean Expressions

The uninitialized values of the primitive data types evaluate to false when coerced in a Boolean expression, but they don’t all evaluate to true in other cases. The number 1 coerces to true, but other numbers evaluate to false. Boolean expressions that contain null or undefined values always evaluate to false unless you are comparing to null or undefined. Consider this example (http://jsfiddle.net/DougWare/xrGjV/1/).


Pretty weird eh? The key takeaway is that you should not rely on type coercion in your boolean expressions because the rules are bizarre.

Every Rule has an Exception

The one scenario where I think it is generally OK to leverage type coercion is when you need to initialize an argument to a function that wasn’t supplied by the caller. This technique relies on the fact that undefined values in boolean expressions evaluate to false in conjunction with the boolean or operator, | (http://jsfiddle.net/DougWare/uY6MR/1/).


Explicit Casts

The previous example is still a bit lazy because it doesn’t validate that the argument is a valid type, but in my opinion it is perfectly correct to throw an error if you expect a named argument to be of one type but the caller provides a different type. However, there are still many situations where you might need to cast a value, especially when you need a number from HTML text like the value of an input field. The basic cast functions are:

  • Number()
  • String()
  • Boolean()

Perhaps unsurprisingly, these don’t behave quite the same way their implicit coercions do (http://jsfiddle.net/DougWare/7hHjd/).


This post completely ignored objects. I’ll talk about those soon, but that I’ll go back to functions and examine the scary sounding but simple concept of closures.

Next: JavaScript for the C# Developer Part 5 – Closures are Simple

–Doug

Author: Doug Ware