获取 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】:

我想这里最通用的解决方案是先检查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,我们有函数返回的适当字符串。 谢谢 - 删除我的 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 Explorer ActiveXObject 实例。 如果你创建了自己的对象类型(原型继承),你怎么能让它返回比“对象”更具体的值?这也作为问题 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 之类的东西,而不是您期望的对象名称。所以要注意这一点——尤其是如果你只在生产中缩小。 nullundefined 很遗憾没有构造函数。 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 变量类型的更好方法?的主要内容,如果未能解决你的问题,请参考以下文章

浅谈javaScript数据类型变量内存之间的关系,文末有图解

如何在javascript变量中获取变量值后面的C#代码?

关于JavaScript的变量的数据类型的判断方法

JavaScript高级程序设计(复制变量值传递参数)

JavaScript使用构造函数获取变量的类型名

JavaScript使用构造函数获取变量的类型名