【问题标题】:The most accurate way to check JS object's type?检查 JS 对象类型的最准确方法?
【发布时间】:2011-12-15 04:17:45
【问题描述】:

typeof 运算符并不能真正帮助我们找到对象的真实类型。

我已经看过以下代码:

Object.prototype.toString.apply(t)  

问题:

这是检查对象类型的最准确的方法吗?

【问题讨论】:

标签: javascript


【解决方案1】:

JavaScript 规范提供了一种确定对象类别的正确方法:

Object.prototype.toString.call(t);

http://bonsaiden.github.com/JavaScript-Garden/#types

【讨论】:

  • 如果您正在寻找一种特定的类型,您可能希望按照以下方式进行操作:Object.prototype.toString.call(new FormData()) === "[object FormData]",这是正确的。您也可以使用slice(8, -1) 返回FormData 而不是[object FormData]
  • 使用Object.prototype{}有什么区别吗?
  • 也许这几年已经改变了,但是 Object.prototype.toString.call(new MyCustomObject()) 返回 [object Object]new MyCustomObject() instanceOf MyCustomObject returns true 这是我想要的(Chrome 54.0.2840.99 m)
  • @Maslow,我遇到了你提出的同样问题。在网上浏览了一些文档后,我最终使用了new MyCustomObject().constructor === MyCustomObject
  • 这引出了一个问题,为什么他们没有用更方便的方法包装这段代码,或者允许额外的运算符编译到这个。我知道你只是信使,但坦率地说,这很糟糕。
【解决方案2】:

Object.prototype.toString 是个好办法,但性能最差。

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

使用typeof 解决一些基本问题(字符串、数字、布尔值...)并使用Object.prototype.toString 解决一些复杂问题(如数组、日期、正则表达式)。

这是我的解决方案:

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));

用作:

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

【讨论】:

  • 对 jsPerf 的测试不太准确。这些测试不相等(测试相同的东西)。例如,typeof [] 返回“object”,typeof {} 也返回“object”,即使一个是对象数组,另一个是对象 Object。该测试还有许多其他问题...在查看 jsPerf 时要小心,因为测试是在将 Apple 与 Apple 进行比较。
  • 您的type 函数很好,但看看它与其他一些type 函数相比如何。 http://jsperf.com/code-type-test-a-test
  • 这些性能指标应该有一些常识。当然,prototype.toString 比其他的要慢一个数量级,但总体而言,每次调用平均需要几百 纳秒。除非此调用用于非常频繁执行的关键路径,否则这可能是无害的。我宁愿有直接的代码,也不愿完成快一微秒的代码。
  • ({}).toString.call(obj)Object.prototype.toString jsperf.com/object-check-test77
  • 不错的解决方案。我将您的功能借入我的库中:)
【解决方案3】:

公认的答案是正确的,但我喜欢在我构建的大多数项目中定义这个小实用程序。

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]',
}

这样使用:

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

}

如果您使用的是 Angular,您甚至可以将其干净地注入:

angular.constant('types', types);

【讨论】:

    【解决方案4】:
    var o = ...
    var proto =  Object.getPrototypeOf(o);
    proto === SomeThing;
    

    保留您期望对象拥有的原型的句柄,然后与它进行比较。

    例如

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

    【讨论】:

    • 这比o instanceof String; //true 更好/不同?
    • @jamietre 因为"foo" instanceof String 中断
    • 好的,所以“typeof(o) === 'object' && o instanceof SomeObject”。测试字符串很容易。只是看起来像是额外的工作,没有解决必须提前知道要测试什么的基本问题。
    • 对不起,代码 sn-p 没有意义,但我想你知道我的意思,如果你正在测试字符串,那么请改用 typeof(x)==='string'
    • 顺便说一句,Object.getPrototypeOf(true) 失败,(true).constructor 返回 Boolean
    【解决方案5】:

    我认为这里显示的大多数解决方案都存在过度设计的问题。检查一个值是否为[object Object] 类型的最简单方法可能是检查它的.constructor 属性:

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

    使用箭头功能甚至更短:

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

    a != null 部分是必需的,因为可能会传入nullundefined,而您无法从其中任何一个中提取构造函数属性。

    它适用于通过以下方式创建的任何对象:

    • Object 构造函数
    • 文字{}

    它的另一个简洁功能是能够为使用Symbol.toStringTag 的自定义类提供正确的报告。例如:

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

    这里的问题是当在它的一个实例上调用Object.prototype.toString时,会返回错误的报告[object Object]

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

    但是检查构造函数会给出正确的结果:

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

    【讨论】:

      【解决方案6】:

      找出对象的真实类型(包括原生对象或数据类型名称(如字符串、日期、数字、..等)和对象的真实类型(甚至是自定义的))的最佳方法;就是通过抓取对象原型的构造函数的name属性:

      原生类型 Ex1:

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

      显示:

      String
      

      Ex2:

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

      显示:

      Array
      

      自定义类:

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

      显示:

      CustomClass
      

      【讨论】:

      • 如果对象是nullundefined,则会失败。
      【解决方案7】:

      我知道的老问题。你不需要转换它。看到这个函数:

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

      例子:

      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
      

      成本低且简单。

      【讨论】:

      • 如果测试对象是nullundefined,则返回false
      • truefalse
      • @JulianKnight false 可以为 null 或 undefined,它没有任何用处。那么有什么意义呢?
      • 您的示例返回的数据不一致。有些结果是数据类型,有些是值false。这对回答问题有何帮助?
      • @JulianKnight 看到变化,这是你想要的吗?如果您更喜欢 undefined 或 "undefined" 作为结果,您可以根据需要替换最后一个 false。
      【解决方案8】:

      最佳解决方案toString(如上所述):

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

      公平警告: toStringNaN 视为 number,因此您必须稍后使用 Number.isNaN(value) 手动保护。

      建议的另一个解决方案,使用 Object.getPrototypeOf failsnullundefined

      【讨论】:

      • 对于 NaN 保护,使用 Number.isNan(+value) 来处理通过 new Number(NaN) 定义值的情况。
      • @Ed_Johnsen 感谢您指出这一点!确实Number.isNaN(new Number(NaN)) // falseNumber.isNaN(+(new Number(NaN))) // true
      【解决方案9】:

      受上述正确答案的启发,我整理了一个小型类型检查实用程序:

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

      示例:

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

      【讨论】:

      • 似乎不适用于 nullundefinedtruefalse 的对象
      猜你喜欢
      • 1970-01-01
      • 2020-07-01
      • 2020-04-01
      • 2011-08-10
      • 2011-11-10
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多