Type detection

  1. Typeof operator
    1. Only primitive values
    2. A good use of typeof
    3. A bad use of typeof
  2. [[Class]] to differ between native objects
  3. Checking type for custom objects
  4. Summary

Polymorphic functions is a great concept of programming. That’s a function which treats parameters differently, depending on their type.

To support polimorphism, we need a way to get the type of a variable. There is a small JS zoo here, let’s check it out.

As we know, there are several primitive types in JavaScript:

null, undefined
Special values.
number
All numbers like 0 and 3.14. Also pseudo-numerical values NaN and Infinity
boolean
True and false values.
string
Strings, like “Meow” and “”.

All other values are objects. For example, functions and arrays are objects.

Typeof operator

The typeof operator takes a value and return it’s type. There are two possible syntaxes:

  1. Operator: typeof x
  2. Function-like: typeof(x)

Both syntaxes work same, but the first one is shorter.

typeof undefined // "undefined" 

typeof 0    // "number" 
 
typeof true // "boolean" 

typeof "foo" // "string" 

typeof {} // "object" 

*!*
typeof null  // "object" 
typeof function(){} // "function" 
typeof NaN  // "number"
*/!*

You see, the three last lines are red. That’s for a reason.

  1. First, the typeof null == "object" is a official mistake in the language, carefully kept from 90x for compatibility.

    We can check it:

    var x = null
    x.prop = 1 // error, can't assign a property to primitive
    

  2. Functions are still objects despite of their special treatment.
  3. The typeof NaN == 'number' is funny, because NaN is an acronym for ‘Not-A-Number’ Smile

Only primitive values

The typeof works sufficiently well with primitive values (except null). But it says nothing about object types.

The typeof can’t distinguish between objects.

For example, Object, Array and Date objects are same.

alert( typeof {} ) // 'object'
alert( typeof [] ) // 'object'
alert( typeof new Date ) // 'object'

We can also see the difference between a primitive string and new String:

alert( typeof "lalala" ) // string
alert( typeof new String("lalala") ) // object

A good use of typeof

Let’s write a polymorphic function.

function f(x) {
 if (typeof x == 'function') {
    ... // in case when x is a function
  } else {
    ... // in other cases
  }
}

That was a fair use.

A bad use of typeof

Now the antipattern. In old code you can find a test for variable existence with typeof:

// check if global variable jQuery exists
if (typeof(jQuery) !== 'undefined') ...

The typeof is used here, because a direct usage of an undefined variable would lead to an error:

// error if jQuery is not defined
if (jQuery) { .. }

Don’t use typeof this way.

A global variable can be accessed as a property of built-in window object. Let’s check it:

if (window.jQuery !== undefined) { ... }

There will be no error, because no one asks for (probably undefined) jQuery. We are just asking the object property.

In most cases, like here, we know that jQuery can’t be falsy if it exists, so the check shortens to:

if (window.jQuery) { ... }

The typeof shouldn’t be used to check for variable existance.

[[Class]] to differ between native objects

The main problem with typeof is that it doesn’t tell much about the object. The function is an exception.

alert( typeof {key:'val'} ) // Object is object
alert( typeof [1,2] ) // Array is object
alert( typeof new Date ) // Date object

Fortunately, there is a hidden [[Class]] property in all JavaScript native objects. It equals “Array” for arrays, “Date” for dates etc.

This property is not accessible directly, but toString, borrowed from native Object returns it with a small wrapping:

var toClass = {}.toString // (1)

alert( toClass.call( [1,2] ) ) // [object Array]
alert( toClass.call( new Date ) ) // [object Date]

Here’s what we do:

  1. Copy a reference to toString for objects into toClass variable.
  2. Call it, but provide the object which we are going to check as this. So, object toString becomes applied to arrays, dates etc. We have to do it, because their own toString behaves differently. For arrays it returns element list, for dates it returns the string representation.

The method also works on primitives:

alert( toClass.call(123) ) // [object Number]
alert( toClass.call("primitive")) ) // [object String

… With exception of null and undefined, because calling call with null or undefined passes window as this.

The [[Class]] is “Object” for custom objects:

function Animal(name) { 
  this.name = name
}
var animal = new Animal("Goofy")
var class = {}.toString.apply( animal )
alert(class) // [object Object]

So, it is useful only for native objects.

Checking type for custom objects

For objects, created by constructor functions, we usually use instanceof operator.

It’s syntax is obj instanceof Func:

function Animal(name) { 
  this.name = name
}
var animal = new Animal("Goofy")

alert( animal instanceof Animal ) // true

We talk more about it in the article The "instanceof" operator.

As of now, for native objects [[Class]] approach is better and is used in most frameworks.

Why not "`arr instanceOf Array`" ?

We could detect an array by using the instanceOf operator:

var arr = [1,2,3]
alert(arr instanceof Array) // true

Although, it will not work if arr was created in another window or iframe and then passed into current window. That’s because each window has it’s own object hierarchy.

To workaround that, most frameworks use [[Class]] for native objects.

Summary

typeof
Good for primitives and functions, it lies about null.
[[Class]]
Exposed through {}.toString. Good for built-in object and primitives, excepts null and undefined.
instanceof
Works for custom objects. Can be used for native objects too, but lies if they come from another frame/window.

Tutorial

Donate

Donate to this project