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

在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

有没有更好的办法?

398292 次浏览

你可以尝试使用constructor.name

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

就像所有JavaScript一样,最终总会有人指出这在某种程度上是邪恶的,所以这里有一个答案的链接很好地涵盖了这一点。

另一种方法是使用Object.prototype.toString.call

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

你可以将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]

一个相当好的类型捕获函数是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

安格斯·克罗尔最近写了一篇有趣的博文

http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ < a href = " 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()
}

一行函数:

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

给出与jQuery.type()相同的结果

我们也可以改变ipr101中的一个小例子

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

并调用as

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

你可能会发现以下函数很有用:

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

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

const { toString } = Object.prototype;


function typeOf(obj) {
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
typeOf(async function() {}) //asyncfunction

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

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¢!实际上,尽管答案列表很长,但我在这里抛出这个问题的部分原因是为了提供更多的< em > all in one < / em >类型的解决方案,并在未来获得一些关于如何扩展它以包含更多< em > real types < / em >的反馈。

下面的解决方案,如前所述,我结合了在这里找到的几个解决方案,以及合并了一个修复,用于在jQuery定义的对象< em >如果可用< / em >上返回jQuery < kbd > < / kbd >的值。我还将该方法附加到本机Object原型。我知道这通常是禁忌,因为它可能会干扰其他类似的扩展,但我把它留给user beware。如果你不喜欢这样做,只要复制基函数到你喜欢的任何地方,然后用传入的参数形参替换this的所有变量(比如参数[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等…)创建的,请随时评论或编辑这篇文章,让它更加准确和精确。或者转到我为它创建的< kbd > GitHub < / kbd >并让我知道。你还可以在那里找到一个指向cdn min文件的快速链接。

我想这里最通用的解决方案是先检查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'

typeof条件用于检查变量类型,如果你在if-else条件下检查变量类型 例如< / p >

if(typeof Varaible_Name "undefined")
{


}

这是一个更完整的版本:

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 type(theThing) {
return Object.prototype.toString.call(theThing).match(/\s([\w]+)/)[1].toLowerCase()
}
type({})           //-> 'object'
type([])           //-> 'array'
type(function(){}) //-> 'function'
    

type(null)         //-> 'null'
type(undefined)    //-> 'undefined
type(true)         //-> 'boolean'
type('hello')      //-> 'string'
type(42)           //-> 'number'


type(Symbol())     //-> 'symbol'
type(/abc/)        //-> 'regexp'
type(new Set())    //-> 'set'
// etc ...

PS:上面的F.NiX做了更健壮的版本,它还告诉你从Class或构造函数中创建的自定义对象的名称。

https://npmjs.com/package/advanced-type

为此我创建了一个包。