Javascript 为什么Object.prototype.toString.call(foo)可以检测到foo';s型?

Javascript 为什么Object.prototype.toString.call(foo)可以检测到foo';s型?,javascript,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()); // [objec

我知道我们可以在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
做什么?

基本上返回对象的
[[Class]]
(实现细节)内部属性。引用ECMA脚本5.1规范,其中定义了

  • 如果
    值为
    未定义
    ,则返回
    “[对象未定义]”
  • 如果
    值为
    ,则返回
    “[对象空]”
  • O是调用
    ToObject
    并将
    此值作为参数传递的结果
  • 让class成为O的
    [[class]]
    内部属性的值
  • 返回串接三个字符串的结果字符串值
    “[对象”
    ,和
    “]”
  • 而且

    [[Class]]
    内部属性的值由本规范为每种内置对象定义。主机对象的
    [[Class]]
    内部属性的值可以是除
    “参数”
    “数组”
    “布尔值”
    “日期”
    “错误”
    “函数”
    “JSON”
    “数学”
    “数字”
    “对象”
    “RegExp”
    “String”
    [[Class]]]
    内部属性的值在内部用于区分不同类型的对象。请注意,此规范不提供程序访问该值的任何方法,除非通过
    对象.prototype.toString


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

    如果您碰巧使用的是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'
    。然后需要注意的是,必须处理
    null
    未定义的
    等问题

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

    类似的事情是