[javascript] The most accurate way to check JS object's type?

The typeof operator doesn't really help us to find the real type of an object.

I've already seen the following code :

Object.prototype.toString.apply(t)  

Question:

Is it the most accurate way of checking the object's type?

This question is related to javascript

The answer is


I put together a little type check utility inspired by the above correct answers:

thetypeof = function(name) {
        let obj = {};
        obj.object = 'object Object'
        obj.array = 'object Array'
        obj.string = 'object String'
        obj.boolean = 'object Boolean'
        obj.number = 'object Number'
        obj.type = Object.prototype.toString.call(name).slice(1, -1)
        obj.name = Object.prototype.toString.call(name).slice(8, -1)
        obj.is = (ofType) => {
            ofType = ofType.toLowerCase();
            return (obj.type === obj[ofType])? true: false
        }
        obj.isnt = (ofType) => {
            ofType = ofType.toLowerCase();
            return (obj.type !== obj[ofType])? true: false
        }
        obj.error = (ofType) => {
            throw new TypeError(`The type of ${name} is ${obj.name}: `
            +`it should be of type ${ofType}`)
        }
        return obj;
    };

example:

if (thetypeof(prop).isnt('String')) thetypeof(prop).error('String')
if (thetypeof(prop).is('Number')) // do something

I'd argue that most of the solutions shown here suffer from being over-engineerd. Probably the most simple way to check if a value is of type [object Object] is to check against the .constructor property of it:

function isObject (a) { return a != null && a.constructor === Object; }

or even shorter with arrow-functions:

const isObject = a => a != null && a.constructor === Object;

The a != null part is necessary because one might pass in null or undefined and you cannot extract a constructor property from either of these.

It works with any object created via:

  • the Object constructor
  • literals {}

Another neat feature of it, is it's ability to give correct reports for custom classes which make use of Symbol.toStringTag. For example:

class MimicObject {
  get [Symbol.toStringTag]() {
    return 'Object';
  }
}

The problem here is that when calling Object.prototype.toString on an instance of it, the false report [object Object] will be returned:

let fakeObj = new MimicObject();
Object.prototype.toString.call(fakeObj); // -> [object Object]

But checking against the constructor gives a correct result:

let fakeObj = new MimicObject();
fakeObj.constructor === Object; // -> false

The best way to find out the REAL type of an object (including BOTH the native Object or DataType name (such as String, Date, Number, ..etc) AND the REAL type of an object (even custom ones); is by grabbing the name property of the object prototype's constructor:

Native Type Ex1:

var string1 = "Test";
console.log(string1.__proto__.constructor.name);

displays:

String

Ex2:

var array1 = [];
console.log(array1.__proto__.constructor.name);

displays:

Array

Custom Classes:

_x000D_
_x000D_
function CustomClass(){_x000D_
  console.log("Custom Class Object Created!");_x000D_
}_x000D_
var custom1 = new CustomClass();_x000D_
_x000D_
console.log(custom1.__proto__.constructor.name);
_x000D_
_x000D_
_x000D_

displays:

CustomClass

Old question I know. You don't need to convert it. See this function:

function getType( oObj )
{
    if( typeof oObj === "object" )
    {
          return ( oObj === null )?'Null':
          // Check if it is an alien object, for example created as {world:'hello'}
          ( typeof oObj.constructor !== "function" )?'Object':
          // else return object name (string)
          oObj.constructor.name;              
    }   

    // Test simple types (not constructed types)
    return ( typeof oObj === "boolean")?'Boolean':
           ( typeof oObj === "number")?'Number':
           ( typeof oObj === "string")?'String':
           ( typeof oObj === "function")?'Function':false;

}; 

Examples:

function MyObject() {}; // Just for example

console.log( getType( new String( "hello ") )); // String
console.log( getType( new Function() );         // Function
console.log( getType( {} ));                    // Object
console.log( getType( [] ));                    // Array
console.log( getType( new MyObject() ));        // MyObject

var bTest = false,
    uAny,  // Is undefined
    fTest  function() {};

 // Non constructed standard types
console.log( getType( bTest ));                 // Boolean
console.log( getType( 1.00 ));                  // Number
console.log( getType( 2000 ));                  // Number
console.log( getType( 'hello' ));               // String
console.log( getType( "hello" ));               // String
console.log( getType( fTest ));                 // Function
console.log( getType( uAny ));                  // false, cannot produce
                                                // a string

Low cost and simple.


The best solution is toString (as stated above):

function getRealObjectType(obj: {}): string {
    return Object.prototype.toString.call(obj).match(/\[\w+ (\w+)\]/)[1].toLowerCase();
}

enter image description here

FAIR WARNING: toString considers NaN a number so you must manually safeguard later with Number.isNaN(value).

The other solution suggested, using Object.getPrototypeOf fails with null and undefined

Using constructor


Accepted answer is correct, but I like to define this little utility in most projects I build.

var types = {
   'get': function(prop) {
      return Object.prototype.toString.call(prop);
   },
   'null': '[object Null]',
   'object': '[object Object]',
   'array': '[object Array]',
   'string': '[object String]',
   'boolean': '[object Boolean]',
   'number': '[object Number]',
   'date': '[object Date]',
}

Used like this:

if(types.get(prop) == types.number) {

}

If you're using angular you can even have it cleanly injected:

angular.constant('types', types);

var o = ...
var proto =  Object.getPrototypeOf(o);
proto === SomeThing;

Keep a handle on the prototype you expect the object to have, then compare against it.

for example

var o = "someString";
var proto =  Object.getPrototypeOf(o);
proto === String.prototype; // true

the Object.prototype.toString is a good way, but its performance is the worst.

http://jsperf.com/check-js-type

check js type performance

Use typeof to solve some basic problem(String, Number, Boolean...) and use Object.prototype.toString to solve something complex(like Array, Date, RegExp).

and this is my solution:

var type = (function(global) {
    var cache = {};
    return function(obj) {
        var key;
        return obj === null ? 'null' // null
            : obj === global ? 'global' // window in browser or global in nodejs
            : (key = typeof obj) !== 'object' ? key // basic: string, boolean, number, undefined, function
            : obj.nodeType ? 'object' // DOM element
            : cache[key = ({}).toString.call(obj)] // cached. date, regexp, error, object, array, math
            || (cache[key] = key.slice(8, -1).toLowerCase()); // get XXXX from [object XXXX], and cache it
    };
}(this));

use as:

type(function(){}); // -> "function"
type([1, 2, 3]); // -> "array"
type(new Date()); // -> "date"
type({}); // -> "object"