“Appearances can be deceiving Mr. Anderson” – a.k.a. short code is not always fast code

I used to take pride in my short, bulletproof and elegant String and Number type checks:

// Check whether obj is a Number
obj + 0 === obj

// Check whether obj is a String
obj + '' === obj

I always thought that apart from being short and elegant, they should be faster.

However, some quick tests gave me a cold slap in the face and proved my assertion to be entirely false. When comparing the following 4 methods for string and number type checking:

  1. “My” method (mentioned above)
  2. Object.prototype.toString method: Object.prototype.toString.call(obj) === '[object String]' or Object.prototype.toString.call(obj) === '[object Number]'
  3. Typeof method: typeof obj === 'string' or typeof obj === 'number'
  4. Contructor method: obj.constructor === String or obj.constructor === Number

It turned out that the Object.prototype.toString method was 50% faster than my method, and both typeof and constructor methods were a whopping 150% faster than my method! No wonder jQuery uses the typeof method for their String/Number tests.

Now that I think about it, it does actually make sense – my method converts obj to a String or Number, then concatenates/adds it with another String/Number, then compares value and type. Too much stuff done there to be fast. But I guess I was too innocent and subconsciously thought that it wouldn’t be fair if elegant and short code wasn’t fast too.

Of course the overall time needed for any of these tests was neglible, but it’s a good example of how much appearances can be deceiving – even in programming! ;)

The moral: Never assume. Always test.

So, which method is ideal for String/Number checks? (added afterwards)

The typeof method and my method fail for non-primitive String/Number objects, as you can easily observe if you type in the console:

typeof new String('foo') // 'object'
typeof new Number(5) // 'object'
new String('foo') + '' === new String('foo') // false

This can easily be solved if you also check the type via instanceof (the decrease in speed is negligible):

foo = new String('foo');
typeof foo === 'string' || foo instanceof String
foo + '' === foo || foo instanceof String

Don’t use instanceof alone, since it fails for String and Number primitives. The instanceof method also fails for Strings and Numbers created in another window, since their constructor there is different. Same happens with the Constructor method mentioned above.

It seems that if you need a bulletproof check the only method you can use is the Object.prototype.toString method and luckily, it’s one of the fastest (not the fastest one though), so I guess we can safely elect it as the ideal method for String and Number checks (and not only for arrays, as it was first made popular for).

PS: For anyone wondering what the quote in the title reminds him/her, its from the Matrix Revolutions movie.

  • http://www.gimiti.com/kltan/ Kean

    Nice article, all your posts have depth and are pretty well researched.

    There’s another method to detect object by using instanceof but it’s not very reliable. For example ([1,2,3] instanceof Array) and ([1,2,3].constructor === Array) returns true only when the variable is in the same frame/iframe.

    Object.prototype.toString.call is good for detecting types that typeof sucks at such as Object, Array and Date. Consider this, typeof [], typeof {} and typeof (new Date()) returns “object”.

    Just use the right function to do the job; sometimes you’d have to sacrifice some speed to achieve reliability.

  • http://leaverou.me Lea Verou

    @Kean: Thanks for commenting and for the kind words! You made my day! :D

    As for the instanceof check, it’s good for some type checks (eg. Arrays in single-frame environments, as you already mentioned), but for I omitted it on purpose here, since this post only deals with String and Number checks, and instanceof doesn’t seem very reliable for these.
    Just type in your firebug console the following:

    'foo' instanceof String; // yields false
    5 instanceof Number; //yields false

    On the contrary, instanceof yields true for non-primitive String and Number objects:

    new String('foo') instanceof String; // yields true
    new Number(5) instanceof Number; //yields true

    I’m not sure why that happens but it seems instanceof is not suitable for robust String and Number type checks.

    By the way, your comment inspired me to add another paragraph to the original article. :)