Miaonster
Miaonster

Reputation: 1522

Why can Object.prototype.toString.call(foo) detect foo's type?

I know that we can detect a variable's type in Javascript like this:

Object.prototype.toString.call([]); // [object Array]
Object.prototype.toString.call({}); // [object Object]
Object.prototype.toString.call(''); // [object String]
Object.prototype.toString.call(new Date()); // [object Date]
Object.prototype.toString.call(1); // [object Number]
Object.prototype.toString.call(function () {}); // [object Function]
Object.prototype.toString.call(/test/i); // [object RegExp]
Object.prototype.toString.call(true); // [object Boolean]
Object.prototype.toString.call(null); // [object Null]
Object.prototype.toString.call(); // [object Undefined]

But why?

How are these values ([object Array], [object String]...) returned, and what does Object.prototype.toString do?

Upvotes: 3

Views: 1056

Answers (2)

Decoded
Decoded

Reputation: 1135

If you happen to be using ECMA 6, (Like on NodeJS, or Newer browser tech) you can use the following function to get 'class name'.

// primitives
var array = [], obj = {}, str = "", date = new Date(), 
            num = 1, flt = 1.0, reg = new RegExp(/woohoo/g), 
            bool = true, myType = new MyType(), udf = undefined, nul = null;

// names of various types (primitive and not)
var names = cName(array) + ", " + cName(obj) + ", " + cName(str) + ", " +
            cName(num) + ", " + cName(flt) + ", " + cName(reg) + ", " + 
            cName(bool) + ", " +  cName(date) + ", " + cName(myType) + ", " + 
            cName(MyType) + ", " +  cName(udf) + ", " + cName(nul);

// custom type
function MyType(){}

console.log( names ); 
// output: 
// Array, Object, String, Number, Number, RegExp, Boolean, Date, MyType, MyType, undefined, null

// implementation
function cName(obj){
    // default to non-null value.
    var ret = '';

    if(typeof obj === 'undefined')  { ret = 'undefined';  }
    else if(obj === null)           { ret = String(obj); }

    else if(typeof obj.constructor !== 'undefined' && obj.constructor !== null){
        ret = obj.constructor.name

        if(ret == 'Function')       { ret = obj.name; }
    }

    return ret;
}

Although there really are no 'classes', this helps when being passed something like Array, vs Object, vs. Null and you want to know which one it is.

calling typeof on any of those will return 'object'. Then there is the the caveat of having to deal with things like null and undefined.

Calling Object.prototype.toString() is heavier than accessing constructor.name as there is no conversion from some type to a string, and I believe the constructor and constructor.name are both member variables, not a getter, which means no additional functions are called in retrieving said name.

Upvotes: 0

thefourtheye
thefourtheye

Reputation: 239573

Object.prototype.toString basically returns the [[Class]] (implementation detail) internal property of the objects. Quoting the section from ECMA Script 5.1 specification, where this is defined

  1. If the this value is undefined, return "[object Undefined]".
  2. If the this value is null, return "[object Null]".
  3. Let O be the result of calling ToObject passing the this value as the argument.
  4. Let class be the value of the [[Class]] internal property of O.
  5. Return the String value that is the result of concatenating the three Strings "[object ", class, and "]".

Also,

The value of the [[Class]] internal property is defined by this specification for every kind of built-in object. The value of the [[Class]] internal property of a host object may be any String value except one of "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", and "String". The value of a [[Class]] internal property is used internally to distinguish different kinds of objects. Note that this specification does not provide any means for a program to access that value except through Object.prototype.toString.

So, Object.prototype.toString is the only function which can access the [[Class]] property.

Upvotes: 7

Related Questions