How to get type of some data in JavaScript

We known, sometimes it’s difficult to get the type of some data, by native JavaScript. Especially scripting cross frames.

So, we need some tools to get it accurately. Let’s do it.

Limitations of typeof

JavaScript provides typeof to get the type of some data natively.
But the operator can not detect all types of data in JavaScript.

1
2
3
4
5
6
7
8
9
10
11
typeof undefined              // 'undefined'
typeof 123 // 'number'
typeof Infinity // 'number'
typeof NaN // 'number'
typeof true // 'boolean'
typeof 'abc' // 'string'
typeof function(){} // 'function'
typeof {name: 'uolcano'} // 'object'
typeof null // 'object'
typeof [1,2,3] // 'object'
typeof new (function F(){}) // 'object'

The codes above tell us three things:

  • typeof can detect function type
  • it can detect the primitive values, but not exactly for number type
  • it regards all objects as the base object type, even though null is not an object semantically.

The latter two situation need to be solved.

Refining the number detecting

typeof can not exactly detect Infinity and NaN, so we must detect them separately.

There are some hints: the object window has two methods – window.isNaN and window.isFinite, detect whether a number is ‘Not a Number’, and whether a number is finite, respectively.
So, we just need to deal with them solely, the other number is really a number.

1
2
3
4
5
6
var type = typeof arg;
if(type === 'number') {
if(isNaN(arg)) return 'NaN';
if(!isFinite(arg)) return 'Infinity';
return type;
}

Detecting object type

There two ways to get the correct type of an instance of certain type:

  • Object.prototype.toString can get the type of the built-in object
  • An object’s constructor property references the constructor on the closest prototype chain

Firstly, we retrieve the type of the built-in object, thus the other objects is some non-native object – e.g. BOM object, DOM object and developer-customized object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(typeof arg === 'object') {
var type = Object.prototype.toString.call(arg).slice(8, -1).toLowerCase();
switch(type){
case 'number':
case 'string':
case 'boolean':
return 'object ' + type;
case 'null':
case 'date':
case 'regexp':
return type;
default:
return arg.constructor.toString().match(/function\s*([^\(\s]*)/)[1].toLowerCase();
}
}

The complete codes: