Things I Didn’t Know About JavaScript Types

JavaScript types are weird. At first glance they look normal enough, but under the surface they’re full of insanity.

When I was first starting out with JavaScript, I kept coming across situations where simple pieces of my code would do unexpected things. Writing code felt like building on a shaky foundation.

Part of the problem is that JavaScript was designed to be easy for beginners to use. So it goes out of it’s way to accept whatever you throw at it. Then rather than crash or throw an exception, it will try to help you to do what you want.

JavaScript will try to help you. But it’s terrible at helping you.

The bad news, is that to be effective at JavaScript you need to learn about all of the weird little idiosyncrasies of the language. The good news is that there aren’t that many of them.

This post is my attempt to bring a bunch of the most common ones together. It’s all of the weird little things I had to learn about JavaScript’s base types to become an effective JavaScript developer.

The Basics

First, let’s take a look at the basics. It starts off simply enough, JavaScript only has 6 types:

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

And even better, everything except object is a primitive. Which means they only have values and don’t have methods.

undefined

A variable that has not been assigned has a value of undefined.

var apple;
typeof apple;                  // 'undefined'

In fact a variable that has not even been declared will have a value of undefined.

typeof banana;                 // 'undefined'

A function will return the value of undefined if it does not have an explicit return value.

function pear() {
    // doesn't return anything
}
var result = pear();
typeof result;                 // 'undefined'

And an object will return undefined if you attempt to access a property that it does not have.

var lemon = {};
typeof lemon.orange;           // 'undefined'

undefined can be defined

Oddly enough, the type undefined is actually a value of the global object.  Even weirder, the word ‘undefined’ isn’t a reserved word. So it’s technically possible for undefined to be set to a different value or to be shadowed by a local variable also called ‘undefined’.

If that sounds dangerous, it’s because it is. The only way to safely get a copy of undefined is to use the void operator.

typeof void(0);             // 'undefined'
typeof void 0;              // 'undefined'

null

The null type is a single value that is generally used to explicitly point a reference to a non-existent object.

var apple = null;
typeof apple;               // 'null'

boolean

The boolean type can have one of 2 values: true or false.

number

The number type is a 64-bit floating point number defined by the IEEE 754 standard. This means it’s probably the same as floating point implementations you’ve used in other programming languages.

typeof 1;                // 'number'
typeof 0.1;              // 'number'
typeof 0.00001;          // 'number'

The number type has 3 symbolic values: Infinity, -Infinity and NaN.

// Symbols
1 / 0;                  // Infinity
-1 / 0;                 // -Infinity
parseInt('garbage');    // NaN

Not a number is a number

NaN is actually a value of the number type.

typeof NaN;                 // 'number'

This can lead to some confusing situations when developers attempt to check if a number is by using typeof to check it it’s ‘not a number’.

var apple = parseInt('garbage');
typeof apple               // 'number'

Not a number is not itself

NaN is the only value in JavaScript that isn’t equal to itself. The ECMAScript standard actually has a special rule for this

NaN === NaN                 // false
-Infinity === -Infinity     // true
null === null               // true
undefined === undefined     // true

The excellent underscore.js library even uses this fact in it’s function ‘_.isNaN’.  Check it out here.

Why does 0100 === 64?

JavaScript supports octal number literals. So if you put a leading zero on the number 100, it will be interpreted as 64.

10;                         // 10
010;                        // 8
0100;                       // 64

Why does 0.1 + 0.2 != 0.3?

JavaScript is often criticised for it’s weird math. But this one is a little unfair. JavaScript just uses the IEEE 754 standard which many other programming languages also use. There is nothing inherently wrong with it, but it is easy to misuse.

Part of the confusion arises because JavaScript generally shows you numbers in the same precision that you use.

0.1 + 0.2 === 0.3;             // false

You can see the real underlying numbers by using the toPrecision method.

Note: If you’re wondering why JavaScript lets you call a method on a primitive value, I’ll be covering that at the end of the post.

0.1.toPrecision(18);            // '0.100000000000000006'
0.2.toPrecision(18);            // '0.200000000000000011'
(0.1 + 0.2).toPrecision(18);    // '0.300000000000000044'

Why does 253 == 253 + 1?

The number type can safely represent any integer between -253 and 253.

Inside of this range, JavaScript will do integer arithmetic on integer values. But outside of this range, JavaScript numbers are unsafe. That’s because outside of this range multiple mathematical numbers are represented by the same JavaScript number.

Number.MAX_SAFE_INTEGER;         // 9007199254740991
Number.MIN_SAFE_INTEGER;         // -9007199254740991

Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2; // true

And you can always check if a number is safe or not using the method isSafeInteger

Number.isSafeInteger(9007199254740992 + 1);   // false
Number.isSafeInteger(1);                      // true

Alex Rauschmayer did a great write up of this on his blog here.

string

The string type is used to represent text. Unlike some languages JavaScript strings are immutable. Which means that string concatenation or substitution will not effect the original string but instead create a new string.

object

The object type is the only non-primitive type in JavaScript. Like other programming languages objects can be thought of as a reference to an area in memory. But I think the most effective way to conceptualise JavaScript objects is as a collection of key/value pairs. Like a hash map.

Everything else is an object, even some things that you would think aren’t.

Function

In JavaScript functions are objects which can be called, but they’re still objects.  This leads to some weird behaviour. For example, you can assign a property to a function and then use it as a function and an object.

var apple = function () {
    return 'banana';
}
apple();                 // 'banana'

// Assigning a property to a function
apple.carrot = 'lemon';
a.carrot;                // 'lemon'

// Still works as a function
apple();                 // 'banana'

Array

JavaScript supports array literals which tricks a lot of people into thinking that arrays aren’t objects. But it’s just an object that has methods to let you do array like things with it like traversal and mutation.

So while JavaScript arrays look quite similar to arrays in other languages, they couldn’t be more different. A JavaScript array is really a hashmap where each array value is stored in the hashmap with it’s index for a key.

So you can use it like an array

var apples = [1, 2, 3];
apples.length;             // 3
apples[1];                 // 1

But it’s still an object

typeof apples;             // 'object'

Which means it will do all kinds of weird stuff.

var bananas = [];
bananas[5] = 'some data';

bananas.length;            // 6
for(var i in bananas) {
    // Only runs one time for '5'
}

And even weirder

var carrots = [];
carrots['prop'] = 'some data';

carrots.length;           // 0
for(var i in carrots) {
    // Only runs one time for 'prop'
}

In general, I avoid using for ... in on arrays.

Regex

JavaScript supports regular expression literals but they’re just objects too.

var a = /[0-9]/;
typeof a;           // 'object'

Why can I call methods on primitives?

So now we know that everything is an object except the primitives (undefined, null, boolean, number and string). So then why can you call methods on them?

See how you can call the ‘replace’ method on a primitive string, number and boolean.

'abc'.replace('b', 1);      // 'a1c'
1.0.toString();              // '1'
true.toString();            // 'true'

JavaScript has global objects called Number, Boolean and String. When you attempt to call a Number, Boolean or String method on a primitive number, boolean, or string then JavaScript will try to help you by silently coercing primitives into objects.

To expose what’s really happening we can tuck a new method into the String object prototype and catch the string being an object.

var apple = 'apple';
typeof apple;         // 'string'

String.prototype.whatAmI = function () {
    return typeof this;
}
apple.whatAmI();      // 'object'

typeof apple;         // 'string'

Angus Croll did a really nice writeup of this behaviour here

Calling methods on primitives gets really odd with numbers. JavaScript can’t tell whether the ‘.’ is part of a floating point number or if it’s referencing a method, so you have to be a bit tricky.

1.0.toString();             // '1'
1..toString();              // '1'
1['toString']();            // '1'

Conclusion

I learned a lot writing this blog post. My big takeaway is that:

Professional JavaScript is about finding where the language will try to silently help you, and avoiding those places.

I hope you found this post helpful. If you’d like to dig further into JavaScript types here are some resources I recommend:

Eloquent JavaScript is the best book I’ve ever found on JavaScript. And it’s free!

The ECMAScript standards are surprisingly accessible. When I’m wondering about a specific language feature, often it’s best just to go to the final authority.

Mozilla Developer Network is my go to resource for JavaScript. They have some excellent articles on JavaScript types.