获取 Javascript 变量类型的更好方法?
Posted
技术标签:
【中文标题】获取 Javascript 变量类型的更好方法?【英文标题】:Better way to get type of a Javascript variable? 【发布时间】:2011-11-15 11:13:00 【问题描述】:有没有比typeof
更好的方法在JS中获取变量的类型?这样做时效果很好:
> 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
有没有更好的办法?
【问题讨论】:
仅供参考,Chrome 中的typeof new RegExp(/./); // "function"
问题似乎已在 Chrome 14 中得到修复。
How do I get the name of an object's type in javascript?的可能重复
警告:如果您正在缩小您的 JS 并且您正在使用诸如打字稿类之类的“自定义对象”,那么下面的一些答案最终会为您提供混淆的函数名称,例如 n
而不是预期的原始名称。例如constructor.name
可能会给你n
而不是预期的全名
【参考方案1】:
我知道我很晚才回答这个问题,但对于任何可能偶然发现这个问题的人,我个人还创建了一个类似于公认的函数:
const toType = (param) =>
if (param === NaN) return 'NaN';
else return Object.prototype.toString.call(param).replace('[object ', '').slice(0, -1).toLowerCase();
除了NaN
之外,结果完全相同。
【讨论】:
【参考方案2】:我做了这个函数:
(您应该将其命名为更独特,以免与其他全局名称冲突。)
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 或构造函数创建的自定义对象的名称。
【讨论】:
【参考方案3】:您可能会发现以下功能很有用:
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 通知我:错误、承诺、生成器函数
【讨论】:
谢谢。它也适用于日期对象:typeOf(new Date())
啊,我忘记了 - 谢谢,现在已经包含在内了。
还有typeOf(Promise.resolve())//promise
typeOf(function *() )//generatorfunction
我无法在打字稿中得到这个答案。给出错误:[ts] Cannot redeclare block-scoped variable 'toString'
不确定 TypeScript。你试过ES7版本吗?没有明确声明 toString 可能是原因?【参考方案4】:
这个版本比较完整:
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
但您也可以从类或函数中获取您构造的每个实例或对象的类型:(这在其他答案之间无效,它们都返回对象)
class C
constructor()
this.a = 1
function F()
this.b = 'Foad'
typeOf(new C()) // -> c
typeOf(new F()) // -> f
【讨论】:
嗨,我看到了一种可能的改进(但值得怀疑)-> 如果函数返回自定义的类名/对象名,它应该区分大小写,返回确切的名称。【参考方案5】:typeof
条件用于检查变量类型,如果你在 if-else 条件下检查变量类型
例如
if(typeof Varaible_Name "undefined")
【讨论】:
【参考方案6】:我想这里最通用的解决方案是先检查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'
【讨论】:
据我所知 -.constructor.name
始终包含字符串值。对于 undefined/null,我们有函数返回的适当字符串。
谢谢 - 删除我的 cmets...
由于constructor
是一个继承属性,这对于使用Object.create(null)
创建的对象会中断。简单到可以修复,但是怎么称呼它呢? “[对象空]”?【参考方案7】:
单行函数:
function type(obj)
return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/,"$1").toLowerCase()
这给出与jQuery.type()
相同的结果
【讨论】:
【参考方案8】:我的 2 美分! 真的,尽管答案列表很长,但我在这里抛出这个的部分原因是为了提供更多 all in one
输入解决方案,并在未来获得一些反馈,了解如何扩展它以包含更多real types
。
使用以下解决方案,如前所述,我结合了这里找到的几个解决方案,并合并了一个 fix 用于在 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 min 文件的快速链接。
【讨论】:
如果你这样做(null).realType()
它会给 Uncaught TypeError: Cannot read properties of null (reading 'realType')
【参考方案9】:
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
开头并以]
结尾,但我不确定在每种情况下都是如此。
【讨论】:
【参考方案10】:我们也可以从 ipr101
改变一个小例子Object.prototype.toType = function()
return ().toString.call(this).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
并调用为
"aaa".toType(); // 'string'
【讨论】:
记住孩子们,操作 JavaScript 基础对象会导致兼容性和其他奇怪的问题。尽量在库和大型项目中谨慎使用它!【参考方案11】: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()
【讨论】:
这里有一个有趣的旁注——这可能会破坏将“主机”对象传递给函数的位置。例如,Internet ExplorerActiveXObject
实例。
如果你创建了自己的对象类型(原型继承),你怎么能让它返回比“对象”更具体的值?这也作为问题 here 提出,但从未得到解决。
如果您的类型命名包含 : 或 _ 您可以将此正则表达式扩展为 match(/\s([a-z,_,:,A-Z]+)/)
正则表达式还需要包含诸如Uint8Array
之类的数字。相反,请考虑更通用的match(/\s([^\]]+)/)
,它应该可以处理任何事情。
我建议改用\w
字运算符...【参考方案12】:
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
【讨论】:
【参考方案13】:您可以尝试使用constructor.name
。
[].constructor.name
new RegExp().constructor.name
与所有 JavaScript 一样,最终总会有人指出这在某种程度上是邪恶的,所以 here is a link to an answer 很好地涵盖了这一点。
另一种方法是使用Object.prototype.toString.call
Object.prototype.toString.call([])
Object.prototype.toString.call(/./)
【讨论】:
name
是 ECMAScript 的一个扩展,并不适用于所有浏览器。
由于确认怀疑在 javascript 中完成的所有事情都在某种程度上是邪恶的,因此投票赞成。
EVIL:如果您正在缩小代码,那么 constructor.name
可能最终会变成 n
之类的东西,而不是您期望的对象名称。所以要注意这一点——尤其是如果你只在生产中缩小。
null
和 undefined
很遗憾没有构造函数。
JavaScript 本身就是邪恶的。而且很傻。这个问题没有很好的答案这一事实就是一个活生生的证明。【参考方案14】:
您可以将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]
。
【讨论】:
@Xeon 我觉得对IE的仇恨有点过分了。 IE9 是一个比它的前辈更好的浏览器。 @pessimopoppotamus 但没有人愿意将浏览器更新到 IE9 使用 IE。 IE 9 是朝着正确方向迈出的一步,IE 10 看起来不错。顺便说一句,我提到的错误是 IE 9 中的回归 - 他们在 IE 8 中修复了它。以上是关于获取 Javascript 变量类型的更好方法?的主要内容,如果未能解决你的问题,请参考以下文章