获取Javascript变量类型的更好方法?


260

是否有比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

有没有更好的办法?


1
仅供参考,typeof new RegExp(/./); // "function"在Chrome中的问题似乎被固定在Chrome 14
user113716


警告:如果您要缩小JS,并且使用的是“自定义对象”(例如打字稿类),那么下面的一些答案将最终给您混淆的函数名称,例如,n而不是预期的原始名称。例如,constructor.name可能会给您n而不是您的全名
Simon_Weaver

Answers:


221

Angus Croll最近写了一篇有趣的博客文章-

http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/

他介绍了各种方法的优缺点,然后定义了一个新方法'toType'-

var toType = function(obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}

3
有趣的旁注-这可能会破坏将“主机”对象传递给函数的位置。ActiveXObject例如,Internet Explorer 实例。
Andy E

如果创建了自己的对象类型(原型继承),那么如何获得比“对象”更具体的值呢?这在这里也是一个问题,但从未得到解决。
EleventyOne 2013年

1
如果您的类型命名包含:或_,则可以将此正则表达式扩展到match(/\s([a-z,_,:,A-Z]+)/)
2014年

6
正则表达式还需要包含诸如之类的数字Uint8Array。相反,考虑match(/\s([^\]]+)/)应该处理任何事情的更一般的方法。
莉莉·芬利

2
我建议改用\w运算符一词…
kaiser

51

您可以尝试使用constructor.name

[].constructor.name
new RegExp().constructor.name

与所有JavaScript一样,最终人们总是会指出这在某种程度上是邪恶的,因此,这里有一个答案的链接,涵盖了这一方面。

替代方法是使用 Object.prototype.toString.call

Object.prototype.toString.call([])
Object.prototype.toString.call(/./)

10
name是ECMAScript的扩展,无法在所有浏览器中使用。
安迪E

16
由于确认怀疑用javascript完成的所有操作都是邪恶的,因此投票否决了。
liljoshu

1
邪恶:如果您要压缩代码,那么constructor.name最终可能会变成类似n您期望的对象名称之类的东西。因此,请注意这一点-特别是如果您仅在生产中尽量减少时。
Simon_Weaver

null并且undefined不幸的是没有构造函数。
Andrew Grimm '18

JavaScript本身就是邪恶的。真傻 这个问题没有好的答案这一事实是对此的有力证明。
user2173353

38

一个不错的类型捕获功能是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对象来添加更多原语。请注意,typeof HTMLElementCollection在Safari中将报告function,但type(HTMLElementCollection)将返回object


31

您可能会发现以下功能有用:

function typeOf(obj) {
  return {}.toString.call(obj).split(' ')[1].slice(0, -1).toLowerCase();
}

或在ES7中(如果有进一步改进,请评论)

function typeOf(obj) {
  const { toString } = Object.prototype;
  const stringified = obj::toString();
  const type = stringified.split(' ')[1].slice(0, -1);

  return type.toLowerCase();
}

结果:

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

感谢@johnrees通知我:错误,承诺,生成器功能


谢谢你 它也适用于日期对象:typeOf(new Date())
James Irwin

啊,我忘了-谢谢,现在已包括在内。
Vix

1
typeOf(Promise.resolve())//promise typeOf(function *() {})//generatorfunction
johnrees

我无法在打字稿中得到这个答案。给出错误:[ts] Cannot redeclare block-scoped variable 'toString'
DauleDK '17

不确定TypeScript。您是否尝试过ES7版本?没有明确声明toString可能是原因?
Vix

15

我们也可以从ipr101更改一个小例子

Object.prototype.toType = function() {
  return ({}).toString.call(this).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}

并称为

"aaa".toType(); // 'string'

6
记住,孩子们,操纵JavaScript基础对象可能导致兼容性和其他奇怪的问题。尝试在库和较大的项目中谨慎使用此功能!
亚历山大·克拉格斯

9

一线功能:

function type(obj) {
    return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/,"$1").toLowerCase()
}

这给出了与 jQuery.type()


3

您可以应用于Object.prototype.toString任何对象:

var toString = Object.prototype.toString;

console.log(toString.call([]));
//-> [object Array]

console.log(toString.call(/reg/g));
//-> [object RegExp]

console.log(toString.call({}));
//-> [object Object]

除IE以外,这在所有浏览器中均能很好地工作-在从另一个窗口获取的变量上调用它时,它只会吐出[object Object]


1
@Xeon我认为对IE的仇恨太大了。IE9是一个比其前身更好的浏览器。
艾伦(Aillyn)2011年

4
@pessimopoppotamus,但是没有人会将其浏览器更新为IE9。
Alex Turpin

1
IE 9是朝着正确方向迈出的一步,IE 10看起来还不错。顺便说一下,我提到的错误已在IE 9回归-它们固定在IE 8
安迪Ë

3

我的2美分!确实,尽管答案很长,但我在这里提出这个问题的部分原因是为了提供更多all in one类型的解决方案,并在将来获得一些反馈,以了解如何扩展它以包含更多内容real types

如前所述,通过以下解决方案,我结合了此处找到的几个解决方案,并结合了一个修复程序,用于jQuery在jQuery定义的对象(如果有)上返回值。我还将方法附加到本机Object原型。我知道这通常是禁忌,因为它可能会干扰其他此类扩展,但我将其留给了user beware。如果您不喜欢这种方式,只需将基础函数复制到任何您喜欢的地方,然后将所有的变量替换为this要传递的参数参数(例如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,则返回值总是小写

更多示例:

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

如果您有什么补充可能对您有所帮助,例如定义何时使用其他库(Moo,Proto,Yui,Dojo等)创建对象,请随时进行注释或编辑,并将其保持下去。准确而精确。或滚动到GitHub我为此所做的事情,并让我知道。您还可以在此处找到指向CDN分钟文件的快速链接。


2
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和结尾,]但是我不确定在每种情况下都是如此。


2

我想这里最普遍的解决方案-是检查undefinednull第一次,然后就打电话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'

据我所知- .constructor.name始终包含字符串值。对于undefined / null,我们具有函数返回的适当字符串。
Arsenowitch

谢谢-删除我的评论…
Bergi

由于constructor是继承的属性,因此对于使用创建的对象会中断Object.create(null)。修复起来很简单,但是又叫什么呢?“ [对象空]”?
traktor53

0

typeof condition用于检查变量类型,如果您在if-else条件下检查变量类型,例如

if(typeof Varaible_Name "undefined")
{

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