Be careful with those primitives types

September 21, 2015

This is probably a refresher for most, but I was curious about how js is handling typing. After all we have String, Number, and Boolean global objects that have these wonderful prototypes that get us some really handy functions. So we can do something like:

console.log("HELLO, I'M TALKING SOFTLY".toLowerCase());
// hello, i'm talking softly

Neat, and because we have these global objects we can augment their prototypes to give us access to extra methods on every instance. For example:

String.prototype.exclamation = function() {
return this.toUpperCase() + "!!!";
console.log("hello, I'm talking loudly".exclamation());

Ember.js augments prototypes to make things a little easier and to quickly get access to methods without having to pass it into an Ember object. This is something that requires a lot of responsibility, as there is some overhead involved and generally you don’t want to surprise people who share the environment with you.

Augmenting prototypes is also useful to polyfill functionality that might not exist, like in older versions of IE.

Prototypes also help with defining inheritance in javascript. We have useful operators like instanceof and typeof to help us make sense of these. Where things get tricky is when you have a primitive like "hello, I'm talking loudly" being a string primitive, but also having access to the String  prototype, like how I added the exclamation method.

We would expect that since we are using a method on the String prototype, and that "hello, I'm talking loudly" was able to access it, that “hello, I’m talking loudly” instanceof String would equal true, but it doesn’t. Oddly enough, typeof “hello, I’m talking loudly” equals “string”, and new String(“hello, I’m talking loudly”) instanceof String equals true.

If all that seems a little confusing it did to me, too. Here is a quick summary of what we’re looking at:

// using new
new String("hello world") instanceof String // true
tyepof new String("hello world") // 'object'
// primitive
"hello world" instanceof String // false
typeof "hello world" // 'string'
// Bonus: without using new
String("hello world") instanceof String // false
tyepof String("hello world") // 'string'

What is happening is that when you use “quotes” or call the function without the operator new you actually are working on the primitive. The primitive isn’t an Object and therefore can’t be an instance. When you aren’t using the new operator, the function is simply returning the primitive. As you might recall, using the new operator on a function uses that function as a constructor and creates an instance that inherits from the function’s prototype. Check out the MDN resource for a better explanation, but essentially we’re dealing with an object.

How are we able to access these method’s on a prototype then? There is something called “autoboxing”, or more commonly as “primitive wrapper types”, happening behind the scenes that wires up methods of a literal to its appropriate Function. You can also do things like this transparently where these “objects” are handled appropriately:

20 * new Number(2) + new Number(2); // 42
20 * new Number(2) + 2; // 42
new Number(20) * new Number(2) + 2; // 42

Interestingly, the typeof for each of these ends up being 'number'

The way these work also affect comparison operators:

console.log(42 == new Number(42)); // true
console.log(42 === new Number(42)); // false

In general, everything works the way you would expect it to except when you’re dealing with matters of “type”. If what you have is a string, number, or boolean and it’s created with the new operator you need to check instanceof String, Number and Function. If it was created as a primitive you need to check typeof value returning ‘string’, ‘number’, ‘boolean’. You could check if either returns true in a helper function, too.

Check out this stackoverflow post for some good discussion about checking types of string, and how using new shouldn’t be used considering the confusion and how unnecessary it is. While it might be in bad style I think it illustrates some of the details behind javascript’s inner workings. Also, I remember reading old javascript examples in books that make use of the new operator to try to ease people in from OOP backgrounds, so you can’t really escape that this exists. There are some interested reads on autoboxing/“primitive wrapper types” to check out, too.

Like many parts of javascript there’s always little gotchas that keep things interesting. Luckily as standards move forward and as people create libraries/frameworks/polyfills to pave the cowpaths, we will end up with an easier way to write javascript. I hope this made sense and if I made any mistakes, or need some clarify anything, please let me know in the comments.