检查JS对象类型的最准确方法?


137

typeof运营商并没有真正帮助我们找到真正的类的一个对象。

我已经看过以下代码:

Object.prototype.toString.apply(t)  

题:

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





3
最准确的方法是...不测试类型。为什么需要类型?
hugomg 2011年

Object.prototype.toString.call / Object.prototype.toString.apply
xgqfrms

Answers:


191

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

Object.prototype.toString.call(t);

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


5
如果您正在寻找一种特定的类型,则可能需要按照以下方式进行操作:Object.prototype.toString.call(new FormData()) === "[object FormData]"正确。您也可以使用slice(8, -1)返回FormData而不是[object FormData]
Chris Marisic 2014年

4
是否有使用什么区别Object.prototype{}
GetFree

3
也许这几年来已经改变了,但是Object.prototype.toString.call(new MyCustomObject())返回[object Object]new MyCustomObject() instanceOf MyCustomObject returns true是我想要的(Chrome 54.0.2840.99 m)
Maslow

@Maslow,我遇到了您提出的同一问题。在网上浏览了一些文档之后,我最终使用了new MyCustomObject().constructor === MyCustomObject
solstice333

3
这就引出了一个问题,为什么他们不使用更方便的方法来包装此代码,或者不允许其他操作员对此进行编译。我知道您只是使者,但坦率地说那太糟糕了。
Andrew S

60

Object.prototype.toString是一个好方法,但是其性能却是最差的。

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

检查js类型的性能

使用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上进行的测试不太准确。这些测试是不相等的(测试同一件事)。例如,即使一个是对象数组,另一个是对象Object,typeof []返回“对象”,typeof {}也返回“对象”。该测试还有很多其他问题...在查看jsPerf时要小心,这些测试将Apple与Apple进行了比较。
kmatheny 2012年

您的type功能不错,但请看它与其他一些type功能的比较。http://jsperf.com/code-type-test-a-test
Progo,2014年

18
应该以一些常识来调整这些性能指标。当然,prototype.toString比其他慢了一个数量级,但在宏伟的方案中,每次调用平均需要数百纳秒。除非在经常执行的关键路径中使用此调用,否则这可能是无害的。我宁愿直接编写代码,也不愿完成一毫秒的代码。
大卫

({}).toString.call(obj)Object.prototype.toString jsperf.com/object-check-test77
timaschew

不错的解决方案。我借用了您的函数到我的lib中:)
Dong Nguyen

19

接受的答案是正确的,但是我喜欢在我构建的大多数项目中定义这个小工具。

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.constant('types', types);

11
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吗?
Jamie Treworgy 2011年

@jamietre因为"foo" instanceof String休息
雷诺斯(Raynos)2011年

好的,所以“ typeof(o)==='object'&& o SomeObject的实例”。测试字符串很容易。看起来好像是一项额外的工作,而无需解决必须事先知道要测试什么的基本问题。
Jamie Treworgy 2011年

抱歉,该代码段毫无意义,但我想您知道我的意思,如果要测试字符串,请typeof(x)==='string'改用。
Jamie Treworgy 2011年

顺便说一句,Object.getPrototypeOf(true)失败的地方(true).constructor返回Boolean
katspaugh 2011年

5

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

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

甚至使用箭头功能更短:

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

a != null部分是必需的,因为可能会传入null或,undefined并且您不能从这两个中的任何一个提取构造函数属性。

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

  • 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

4

找出对象的REAL类型(包括原始Object或DataType名称(例如String,Date,Number,.. etc)和对象的REAL类型(甚至是自定义对象)的最佳方法是通过抓取对象原型的构造函数的name属性:

本机类型Ex1:

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

显示:

String

示例2:

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

如果对象是null或,则此操作将失败undefined
朱利安·奈特

2

我知道的老问题。您不需要转换它。看到这个功能:

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

成本低廉,简单。


返回false如果该测试对象是null或者undefined
朱利安·奈特

truefalse
朱利安·奈特

@JulianKnight false为null或未定义是可以的,它没有用。那有什么意义呢?
6

您的示例返回不一致的数据。一些结果是数据类型,另一些是值false。这如何帮助回答问题?
朱利安·奈特

1
@JulianKnight看到更改,这就是您想要的吗?如果您希望使用undefined或“ undefined”作为结果,则可以替换最后一个false。
6

0

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

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

似乎不适用于nullor undefinedtrueor的对象false
朱利安·奈特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.