为什么Object.prototype.toString.call(foo)可以检测foo的类型?

时间:2015-03-05 15:35:59

标签: javascript

我知道我们可以在Javascript中检测变量的类型:

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]

但为什么呢?

这些值([object Array],[object String] ...)是如何返回的,以及Object.prototype.toString的作用是什么?

2 个答案:

答案 0 :(得分:6)

Object.prototype.toString基本上返回对象的[[Class]](实现细节)内部属性。从ECMA Script 5.1规范中引用the section,其中定义了

  
      
  1. 如果this值为undefined,请返回"[object Undefined]"
  2.   
  3. 如果this值为null,请返回"[object Null]"
  4.   
  5. O 成为调用ToObject传递this值作为参数的结果。
  6.   
  7. class O [[Class]]内部属性的值。
  8.   
  9. 返回串联三个字符串"[object "class"]"的结果的字符串值。
  10.   

此外,

  

[[Class]]内部属性的值由此规范为每种内置对象定义。宿主对象的[[Class]]内部属性的值可以是除"Arguments""Array""Boolean""Date",{{1}之外的任何字符串值},"Error""Function""JSON""Math""Number""Object""RegExp"。内部使用"String"内部属性的值来区分不同类型的对象。 请注意,除了[[Class]]之外,此规范不提供程序访问该值的任何方法。

因此,Object.prototype.toString是唯一可以访问Object.prototype.toString属性的函数。

答案 1 :(得分:0)

如果您正在使用ECMA 6(如在NodeJS或更新的浏览器技术上),您可以使用以下函数来获取“类名”。

// 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;
}

虽然确实没有“课程”,但这有助于传递类似Array, vs Object, vs. Null的内容,并且您想知道它是哪一个。

在其中任何一个上调用typeof都会返回'object'。然后有必须处理nullundefined之类的事情的警告。

调用Object.prototype.toString()比访问constructor.name更重要,因为没有从某种类型转换为字符串,我相信constructorconstructor.name都是成员变量,不是getter,这意味着在检索所述名称时不会调用其他函数。