在JS中有比typeof更好的方法来获取变量的类型吗?当你这样做时,它工作得很好:

> typeof 1
"number"
> typeof "hello"
"string"

但当你尝试的时候,它是无用的:

> typeof [1,2]
"object"
>r = new RegExp(/./)
/./
> typeof r
"function"

我知道instanceof,但这需要您事先知道类型。

> [1,2] instanceof Array
true
> r instanceof RegExp
true

有没有更好的办法?


当前回答

function getType(obj) {
    if(obj && obj.constructor && obj.constructor.name) {
        return obj.constructor.name;
    }
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

在我的初步测试中,这工作得很好。第一种情况将打印用“new”创建的任何对象的名称,第二种情况将捕获其他所有对象。

我使用(8,-1)是因为我假设结果总是以[object]开始,以[object]结束,但我不确定在每种情况下都是这样。

其他回答

这是一个更完整的版本:

const typeOf = obj => {
  let type = ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1]
  if (type === 'Object') {
    const results = (/^(function|class)\s+(\w+)/).exec(obj.constructor.toString())
    type = (results && results.length > 2) ? results[2] : ''
  }
  return type.toLowerCase()
}

现在你不仅可以得到这些结果:(就像这里回答的那样)

undefined or empty -> undefined
null -> null
NaN -> number
5 -> number
{} -> object
[] -> array
'' -> string
function () {} -> function
/a/ -> regexp
new Date() -> date
new Error -> error
Promise.resolve() -> promise
function *() {} -> generatorfunction
new WeakMap() -> weakmap
new Map() -> map

但你也可以从类或函数中获得你构造的每个实例或对象的类型:(在其他答案之间无效,它们都返回object)

class C {
  constructor() {
    this.a = 1
  }
}

function F() {
  this.b = 'Foad'
}

typeOf(new C()) // -> c
typeOf(new F()) // -> f
function getType(obj) {
    if(obj && obj.constructor && obj.constructor.name) {
        return obj.constructor.name;
    }
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

在我的初步测试中,这工作得很好。第一种情况将打印用“new”创建的任何对象的名称,第二种情况将捕获其他所有对象。

我使用(8,-1)是因为我假设结果总是以[object]开始,以[object]结束,但我不确定在每种情况下都是这样。

我的2¢!实际上,我在这里提出这个问题的部分原因(尽管有很长的答案列表)是为了提供更多的一种类型解决方案,并在将来获得一些关于如何扩展它以包括更多真实类型的反馈。

With the following solution, as aforementioned, I combined a couple of solutions found here, as well as incorporate a fix for returning a value of jQuery on jQuery defined object if available. I also append the method to the native Object prototype. I know that is often taboo, as it could interfere with other such extensions, but I leave that to user beware. If you don't like this way of doing it, simply copy the base function anywhere you like and replace all variables of this with an argument parameter to pass in (such as arguments[0]).

;(function() {  //  Object.realType
    function realType(toLower) {
        var r = typeof this;
        try {
            if (window.hasOwnProperty('jQuery') && this.constructor && this.constructor == jQuery) r = 'jQuery';
            else r = this.constructor && this.constructor.name ? this.constructor.name : Object.prototype.toString.call(this).slice(8, -1);
        }
        catch(e) { if (this['toString']) r = this.toString().slice(8, -1); }
        return !toLower ? r : r.toLowerCase();
    }
    Object['defineProperty'] && !Object.prototype.hasOwnProperty('realType')
        ? Object.defineProperty(Object.prototype, 'realType', { value: realType }) : Object.prototype['realType'] = realType;
})();

然后简单地使用,就像这样:

obj.realType()  //  would return 'Object'
obj.realType(true)  //  would return 'object'

注意:有1个参数可传递。如果是true的bool类型,则返回值总是小写。

更多的例子:

true.realType();                            //  "Boolean"
var a = 4; a.realType();                    //  "Number"
$('div:first').realType();                   // "jQuery"
document.createElement('div').realType()    //  "HTMLDivElement"

如果你有任何可能有帮助的东西要添加,比如定义一个对象是什么时候用另一个库(Moo, Proto, Yui, Dojo等…)创建的,请随时评论或编辑这篇文章,让它更加准确和精确。或者转到我为它做的GitHub上,让我知道。你还可以在那里找到一个指向cdn min文件的快速链接。

我想这里最通用的解决方案是首先检查undefined和null,然后调用constructor.name.toLowerCase()。

const getType = v =>
  v === undefined
    ? 'undefined'
    : v === null
      ? 'null'
      : v.constructor.name.toLowerCase();




console.log(getType(undefined)); // 'undefined'
console.log(getType(null)); // 'null'
console.log(getType('')); // 'string'
console.log(getType([])); // 'array'
console.log(getType({})); // 'object'
console.log(getType(new Set())); // `set'
console.log(getType(Promise.resolve())); // `promise'
console.log(getType(new Map())); // `map'

YUI3使用的是一个相当不错的类型捕获函数:

var TYPES = {
    'undefined'        : 'undefined',
    'number'           : 'number',
    'boolean'          : 'boolean',
    'string'           : 'string',
    '[object Function]': 'function',
    '[object RegExp]'  : 'regexp',
    '[object Array]'   : 'array',
    '[object Date]'    : 'date',
    '[object Error]'   : 'error'
},
TOSTRING = Object.prototype.toString;

function type(o) {
    return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
};

这捕获了javascript提供的许多原语,但您总是可以通过修改TYPES对象添加更多原语。注意,Safari中的typeof HTMLElementCollection将报告function,而type(HTMLElementCollection)将返回object