t.888
t.888

Reputation: 3902

General type checking of built-in types with Object.prototype.toString()

I'm wondering if it's appropriate to use Object.prototype.toString() for general type checking with built-in types. I have a function that looks like this:

// Return the built-in type of an object.
var typeOf = (function() {
  var reType = /\[object (\w+)\]/; 
  return function typeOf(obj) {
    return reType.exec(Object.prototype.toString.call(obj))[1];
  };
})();

Calls to the function return the following results:

console.log( typeOf(null) );         // => Null
console.log( typeOf(undefined) );    // => Undefined
console.log( typeOf([]) );           // => Array
console.log( typeOf(true) );         // => Boolean
console.log( typeOf(new Date()) );   // => Date
console.log( typeOf(new Error()) );  // => Error
console.log( typeOf(function(){}) ); // => Function 
console.log( typeOf(1) );            // => Number
console.log( typeOf({}) );           // => Object
console.log( typeOf(/ /) );          // => RegExp
console.log( typeOf("") );           // => String

Is this acceptable other than the fact it might be slower than other forms of type checking?

One of the reasons I'm asking is because I'm wanting to encode and serialize an object's built-in type for a project I'm working on. I'm looking at passing the returned type to a function which returns a numeric code:

// Encode a built-in type as a number.
var encodeType = (function() {
  var types = {
    'Null':      0,
    'Undefined': 1,
    'Array':     2,
    'Boolean':   3,
    'Date':      4,
    'Error':     5,
    'Function':  6,
    'Number':    7,
    'Object':    8,
    'RegExp':    9,
    'String':    10,
    'Arguments': 11,
    'Math':      12,
    'JSON':      13
  };
  return function encodeType(type) {
    return types[type];
  }
})();

So the output becomes:

console.log(encodeType( typeOf(null) ));         // => 0
console.log(encodeType( typeOf(undefined) ));    // => 1
console.log(encodeType( typeOf([]) ));           // => 2
console.log(encodeType( typeOf(true) ));         // => 3
console.log(encodeType( typeOf(new Date()) ));   // => 4
console.log(encodeType( typeOf(new Error()) ));  // => 5
console.log(encodeType( typeOf(function(){}) )); // => 6
console.log(encodeType( typeOf(1) ));            // => 7
console.log(encodeType( typeOf({}) ));           // => 8
console.log(encodeType( typeOf(/ /) ));          // => 9
console.log(encodeType( typeOf("") ));           // => 10

Are there any pitfalls with type checking this way? Thanks for any insights.

Upvotes: 4

Views: 239

Answers (2)

Jonathan Gray
Jonathan Gray

Reputation: 2609

I don't understand all of the extra syntax. Wouldn't this do the exact same thing?

var typeOf = function(obj) {
    var reType = /\[object (\w+)\]/;
    return reType.exec(Object.prototype.toString.call(obj))[1];
    };

Also, it might be better to use a switch for encodeType

Upvotes: 0

Lodewijk Bogaards
Lodewijk Bogaards

Reputation: 19987

Here is underscore.js' implementation:

  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
    _['is' + name] = function(obj) {
      return toString.call(obj) === '[object ' + name + ']';
    };
  });

So yes, this method is good to go.

P.S. toString is short for Object.prototype.toString in the above code.

Upvotes: 3

Related Questions