获取对象类型的名称

是否存在javascript等价于Javaclass.getName()

858128 次浏览

有没有JavaScript等价于Java的class.getName()

<强>不

ES2015更新#0的名字是#1thing的类的名称,无论thing的类型如何,都是thing.constructor.name。ES2015环境中的内置构造函数具有正确的name属性;例如(2).constructor.name"Number"


但这里有各种黑客都以这样或那样的方式倒下:

这是一个可以做你需要做的事情的黑客——注意它修改了对象的原型,这是人们不喜欢的东西(通常是有充分理由的)

Object.prototype.getName = function() {var funcNameRegex = /function (.{1,})\(/;var results = (funcNameRegex).exec((this).constructor.toString());return (results && results.length > 1) ? results[1] : "";};

现在,您的所有对象都将具有函数getName(),它将以字符串形式返回构造函数的名称。我在FF3IE7中测试过这个,我不能说其他实现。

如果您不想这样做,这里讨论了在JavaScript中确定类型的各种方法…


我最近更新了这一点,使其更加详尽,尽管它几乎不是那样。

使用constructor属性…

每个object都有其constructor属性的值,但取决于object的构造方式以及您想对该值执行的操作,它可能有用,也可能不有用。

一般来说,您可以使用constructor属性来测试对象的类型,如下所示:

var myArray = [1,2,3];(myArray.constructor == Array); // true

所以,这对大多数需求来说都很有效。也就是说…

警告

在很多情况下根本不起作用

这种模式虽然破碎,但很常见:

function Thingy() {}Thingy.prototype = {method1: function() {},method2: function() {}};

通过new Thingy构造的Objects将具有constructor属性,该属性指向Object,而不是Thingy。因此,我们从一开始就正确;您根本无法在您无法控制的代码库中信任constructor

多重继承

一个不太明显的例子是使用多重继承:

function a() { this.foo = 1;}function b() { this.bar = 2; }b.prototype = new a(); // b inherits from a

现在的事情并不像你期望的那样工作:

var f = new b(); // instantiate a new object with the b constructor(f.constructor == b); // false(f.constructor == a); // true

因此,如果您的测试的object将不同的object设置为其prototype,您可能会得到意想不到的结果。

constructor属性还有其他用途,其中一些很有趣,另一些则不那么重要;现在我们不会深入研究这些用途,因为它与本讨论无关。

不会工作跨框架和跨窗口

当您想检查来自不同window对象的对象类型时,使用.constructor进行类型检查会中断,例如ifram或弹出窗口。这是因为每个“窗口”中每个核心类型constructor的版本不同,即

iframe.contentWindow.Array === Array // false

使用instanceof运算符…

instanceof运算符也是测试object类型的一种干净方法,但它有自己的潜在问题,就像constructor属性一样。

var myArray = [1,2,3];(myArray instanceof Array); // true(myArray instanceof Object); // true

但是instanceof不能用于文字值(因为文字不是Objects

3 instanceof Number // false'abc' instanceof String // falsetrue instanceof Boolean // false

文字需要包装在Object中才能使instanceof工作,例如

new Number(3) instanceof Number // true

.constructor检查对文字很有效,因为.方法调用隐式地将文字包装在各自的对象类型中

3..constructor === Number // true'abc'.constructor === String // truetrue.constructor === Boolean // true

为什么3是两个点?因为Javascript将第一个点解释为小数点;)

不会工作跨框架和跨窗口

instanceof也不会在不同的窗口中工作,原因与constructor属性检查相同。


使用constructor属性的name属性…

在许多情况下不工作一点也不

再次,见上文;constructor完全错误和无用是很常见的。

不工作在

使用myObjectInstance.constructor.name将为您提供一个字符串,其中包含所使用的constructor函数的名称,但受前面提到的关于constructor属性的警告的约束。

对于IE9及以上版本,您可以猴子补丁支持

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {Object.defineProperty(Function.prototype, 'name', {get: function() {var funcNameRegex = /function\s+([^\s(]+)\s*\(/;var results = (funcNameRegex).exec((this).toString());return (results && results.length > 1) ? results[1] : "";},set: function(value) {}});}

文章中的更新版本。这是在文章发布3个月后添加的,这是文章作者Matthew Scharley推荐使用的版本。此更改受前面代码中的评论指出潜在的陷阱的启发。

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {Object.defineProperty(Function.prototype, 'name', {get: function() {var funcNameRegex = /function\s([^(]{1,})\(/;var results = (funcNameRegex).exec((this).toString());return (results && results.length > 1) ? results[1].trim() : "";},set: function(value) {}});}

使用Object.prototype.to字符串

事实证明,作为这篇文章详细,您可以使用Object.prototype.toString-toString的低级和泛型实现-来获取所有内置类型的类型

Object.prototype.toString.call('abc') // [object String]Object.prototype.toString.call(/abc/) // [object RegExp]Object.prototype.toString.call([1,2,3]) // [object Array]

可以编写一个简短的辅助函数,例如

function type(obj){return Object.prototype.toString.call(obj).slice(8, -1);}

去掉杂物,只得到类型名称

type('abc') // String

但是,对于所有用户定义的类型,它将返回Object


警告所有…

所有这些都受到一个潜在问题的影响,那就是所讨论的对象是如何构造的。以下是构建对象的各种方法以及不同类型检查方法将返回的值:

// using a named function:function Foo() { this.a = 1; }var obj = new Foo();(obj instanceof Object);          // true(obj instanceof Foo);             // true(obj.constructor == Foo);         // true(obj.constructor.name == "Foo");  // true
// let's add some prototypical inheritancefunction Bar() { this.b = 2; }Foo.prototype = new Bar();obj = new Foo();(obj instanceof Object);          // true(obj instanceof Foo);             // true(obj.constructor == Foo);         // false(obj.constructor.name == "Foo");  // false

// using an anonymous function:obj = new (function() { this.a = 1; })();(obj instanceof Object);              // true(obj.constructor == obj.constructor); // true(obj.constructor.name == "");         // true

// using an anonymous function assigned to a variablevar Foo = function() { this.a = 1; };obj = new Foo();(obj instanceof Object);      // true(obj instanceof Foo);         // true(obj.constructor == Foo);     // true(obj.constructor.name == ""); // true

// using object literal syntaxobj = { foo : 1 };(obj instanceof Object);            // true(obj.constructor == Object);        // true(obj.constructor.name == "Object"); // true

虽然并非所有的排列都出现在这组示例中,但希望有足够的内容可以让你了解根据你的需求,事情可能会变得多么混乱。不要假设任何事情,如果你不确切地理解你在追求什么,你可能会因为缺乏潜移默化的微妙之处而在你意想不到的地方得到代码破解。

注:

关于typeof运算符的讨论可能看起来是一个明显的遗漏,但它在帮助识别object是否是给定类型方面真的没有用,因为它非常简单。了解typeof在哪里有用很重要,但我目前不觉得它与这个讨论非常相关。不过,我的思想是开放的。:)

您可以使用#0运算符来查看一个对象是否是另一个对象的实例,但由于没有类,您无法获得类名。

Jason Bunting的回答给了我足够的线索来找到我需要的东西:

<<Object instance>>.constructor.name

例如,在下面的代码中:

function MyObject() {}var myInstance = new MyObject();

myInstance.constructor.name将返回"MyObject"

您可以得到的最接近的是#0,但它仅返回任何类型的自定义类型的“对象”。对于那些,请参阅Jason Bunting

编辑,Jason由于某种原因删除了他的帖子,所以只需使用Object的constructor属性。

您可以使用“instance of”运算符来确定对象是否是某个类的实例。如果您不知道对象类型的名称,您可以使用其构造函数属性。对象的构造函数属性是对用于初始化它们的函数的引用。示例:

function Circle (x,y,radius) {this._x = x;this._y = y;this._radius = raduius;}var c1 = new Circle(10,20,5);

现在c1.constructor是对Circle()函数的引用。您也可以使用typeof运算符,但typeof运算符显示的信息有限。一种解决方案是使用Object全局对象的toString()方法。例如,如果您有一个对象,例如myObject,您可以使用全局Object的toString()方法来确定myObject类的类型。使用此:

Object.prototype.toString.apply(myObject);

我用的一个小把戏:

function Square(){this.className = "Square";this.corners = 4;}
var MySquare = new Square();console.log(MySquare.className); // "Square"

可以时使用constructor.name,不能时使用regex函数。

Function.prototype.getName = function(){if (typeof this.name != 'undefined')return this.name;elsereturn /function (.+)\(/.exec(this.toString())[1];};

更新

准确地说,我认为OP要求一个函数来检索特定对象的构造函数名称。就Javascript而言,object没有类型,而是类型的和本身。然而,不同的对象可以有不同的构造函数

Object.prototype.getConstructorName = function () {var str = (this.prototype ? this.prototype.constructor : this.constructor).toString();var cname = str.match(/function\s(\w*)/)[1];var aliases = ["", "anonymous", "Anonymous"];return aliases.indexOf(cname) > -1 ? "Function" : cname;}
new Array().getConstructorName();  // returns "Array"(function () {})().getConstructorName(); // returns "Function"

 


备注:下面的示例已弃用。

Christian Sciberras链接的博客文章包含一个关于如何做到这一点的好例子。即,通过扩展对象原型:

if (!Object.prototype.getClassName) {Object.prototype.getClassName = function () {return Object.prototype.toString.call(this).match(/^\[object\s(.*)\]$/)[1];}}
var test = [1,2,3,4,5];
alert(test.getClassName()); // returns Array

这是我想出的一个解决方案,它解决了instance of的缺点。它可以从跨窗口和跨帧检查对象的类型,并且不存在原始类型的问题。

function getType(o) {return Object.prototype.toString.call(o).match(/^\[object\s(.*)\]$/)[1];}function isInstance(obj, type) {var ret = false,isTypeAString = getType(type) == "String",functionConstructor, i, l, typeArray, context;if (!isTypeAString && getType(type) != "Function") {throw new TypeError("type argument must be a string or function");}if (obj !== undefined && obj !== null && obj.constructor) {//get the Function constructorfunctionConstructor = obj.constructor;while (functionConstructor != functionConstructor.constructor) {functionConstructor = functionConstructor.constructor;}//get the object's windowcontext = functionConstructor == Function ? self : functionConstructor("return window")();//get the constructor for the typeif (isTypeAString) {//type is a string so we'll build the context (window.Array or window.some.Type)for (typeArray = type.split("."), i = 0, l = typeArray.length; i < l && context; i++) {context = context[typeArray[i]];}} else {//type is a function so execute the function passing in the object's window//the return should be a constructorcontext = type(context);}//check if the object is an instance of the constructorif (context) {ret = obj instanceof context;if (!ret && (type == "Number" || type == "String" || type == "Boolean")) {ret = obj.constructor == context}}}return ret;}

isInstance需要两个参数:一个对象和一个类型。它工作的真正诀窍是它检查对象是否来自同一窗口,如果不是则获取对象的窗口。

示例:

isInstance([], "Array"); //trueisInstance("some string", "String"); //trueisInstance(new Object(), "Object"); //true
function Animal() {}function Dog() {}Dog.prototype = new Animal();
isInstance(new Dog(), "Dog"); //trueisInstance(new Dog(), "Animal"); //trueisInstance(new Dog(), "Object"); //trueisInstance(new Animal(), "Dog"); //false

类型参数也可以是返回构造函数的回调函数。回调函数将接收一个参数,该参数是提供对象的窗口。

示例:

//"Arguments" type checkvar args = (function() {return arguments;}());
isInstance(args, function(w) {return w.Function("return arguments.constructor")();}); //true
//"NodeList" type checkvar nl = document.getElementsByTagName("*");
isInstance(nl, function(w) {return w.document.getElementsByTagName("bs").constructor;}); //true

需要记住的一件事是IE<9并没有在所有对象上提供构造函数,因此上面对NodeList的测试将返回false,isInstance(警报,“Function”)也将返回false。

使用Object.prototype.to字符串

事实证明,正如这篇文章详细介绍的那样,您可以使用Object.prototype.toString-toString的低级和通用实现-来获取所有内置类型的类型

Object.prototype.toString.call('abc') // [object String]Object.prototype.toString.call(/abc/) // [object RegExp]Object.prototype.toString.call([1,2,3]) // [object Array]

可以编写一个简短的辅助函数,例如

function type(obj){return Object.prototype.toString.call(obj]).match(/\s\w+/)[0].trim()}
return [object String] as Stringreturn [object Number] as Numberreturn [object Object] as Objectreturn [object Undefined] as Undefinedreturn [object Function] as Function

Agave.JS中的种类()函数将返回:

  • 继承树中最接近的原型
  • 对于总是基本类型,如'null'和'undefault',基本名称。

它适用于所有JS对象和原语,不管它们是如何被创造出来的,并且没有任何惊喜。

var kind = function(item) {var getPrototype = function(item) {return Object.prototype.toString.call(item).slice(8, -1);};var kind, Undefined;if (item === null ) {kind = 'null';} else {if ( item === Undefined ) {kind = 'undefined';} else {var prototype = getPrototype(item);if ( ( prototype === 'Number' ) && isNaN(item) ) {kind = 'NaN';} else {kind = prototype;}}}return kind;};

示例:

数字

kind(37) === 'Number'kind(3.14) === 'Number'kind(Math.LN2) === 'Number'kind(Infinity) === 'Number'kind(Number(1)) === 'Number'kind(new Number(1)) === 'Number'

NaN

kind(NaN) === 'NaN'

弦乐

kind('') === 'String'kind('bla') === 'String'kind(String("abc")) === 'String'kind(new String("abc")) === 'String'

布尔值

kind(true) === 'Boolean'kind(false) === 'Boolean'kind(new Boolean(true)) === 'Boolean'

数组

kind([1, 2, 4]) === 'Array'kind(new Array(1, 2, 3)) === 'Array'

对象

kind({a:1}) === 'Object'kind(new Object()) === 'Object'

日期

kind(new Date()) === 'Date'

函数

kind(function(){}) === 'Function'kind(new Function("console.log(arguments)")) === 'Function'kind(Math.sin) === 'Function'

未定义

kind(undefined) === 'undefined'

null

kind(null) === 'null'

实际上,我正在寻找类似的东西并遇到了这个问题。这是我如何获得类型:jsfiddle

var TypeOf = function ( thing ) {
var typeOfThing = typeof thing;
if ( 'object' === typeOfThing ) {
typeOfThing = Object.prototype.toString.call( thing );
if ( '[object Object]' === typeOfThing ) {
if ( thing.constructor.name ) {return thing.constructor.name;}
else if ( '[' === thing.constructor.toString().charAt(0) ) {typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );}
else {
typeOfThing = thing.constructor.toString().match( /function\s*(\w+)/ );
if ( typeOfThing ) {return typeOfThing[1];}
else {return 'Function';}}}
else {typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );}}
return typeOfThing.charAt(0).toUpperCase() + typeOfThing.slice(1);}

如果有人正在寻找使用jQuery的解决方案,这里是调整后的wiki代码(原始中断jQuery)。

Object.defineProperty(Object.prototype, "getClassName", {value: function() {var funcNameRegex = /function (.{1,})\(/;var results = (funcNameRegex).exec((this).constructor.toString());return (results && results.length > 1) ? results[1] : "";}});

Lodash有很多is方法,所以如果你正在使用Lodash,也许像这样的混合会很有用:

  // Mixin for identifying a Javascript Object
_.mixin({'identify' : function(object) {var output;var isMethods = ['isArguments', 'isArray', 'isArguments', 'isBoolean', 'isDate', 'isArguments','isElement', 'isError', 'isFunction', 'isNaN', 'isNull', 'isNumber','isPlainObject', 'isRegExp', 'isString', 'isTypedArray', 'isUndefined', 'isEmpty', 'isObject']
this.each(isMethods, function (method) {if (this[method](object)) {output = method;return false;}}.bind(this));return output;}});

它为洛达什添加了一个名为“识别”的方法,其工作方式如下:

console.log(_.identify('hello friend'));       // isString

Plunker:http://plnkr.co/edit/Zdr0KDtQt76Ul3KTEDSN

好的,伙计们,多年来我一直在慢慢地为这个建立一个捕获所有方法,哈哈!诀窍是:

  1. 有一个创建类的机制。
  2. 有一种机制来检查所有用户创建的类、原语和本机构造函数创建/生成的值。
  3. 有一种机制可以将用户创建的类扩展到新的类中,以便上述功能渗透到您的代码/应用程序/库/等中。

有关示例(或查看我如何处理问题),请查看github上的以下代码:https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js并搜索:

classOf =classOfIs =或者defineSubClass =(没有反向标记 (`)).

正如你所看到的,我有一些机制来强制classOf总是给我类/构造函数类型名称,无论它是原始的、用户定义的类、使用本机构造函数创建的值、Null、NaN等。对于每一个javascript值,我将从classOf函数中获得它的唯一类型名称。此外,我可以将实际构造函数传入sjl.classOfIs以检查值的类型,此外还可以传入它的类型名称!例如:

"'//名字空间太长了不好意思,用了一段时间才知道有什么影响,太烂了哈哈

var SomeCustomClass = sjl.package.stdlib.Extendable.extend({constructor: function SomeCustomClass () {},// ...}),
HelloIterator = sjl.ns.stdlib.Iterator.extend(function HelloIterator () {},{ /* ... methods here ... */ },{ /* ... static props/methods here ... */ }),
helloIt = new HelloIterator();
sjl.classOfIs(new SomeCustomClass(), SomeCustomClass) === true; // `true`sjl.classOfIs(helloIt, HelloIterator) === true; // `true`
var someString = 'helloworld';
sjl.classOfIs(someString, String) === true; // `true`
sjl.classOfIs(99, Number) === true; // true
sjl.classOf(NaN) === 'NaN'; // true
sjl.classOf(new Map()) === 'Map';sjl.classOf(new Set()) === 'Set';sjl.classOfIs([1, 2, 4], Array) === true; // `true`
// etc..
// Also optionally the type you want to check against could be the type's namesjl.classOfIs(['a', 'b', 'c'], 'Array') === true; // `true`!sjl.classOfIs(helloIt, 'HelloIterator') === true; // `true`!

"'

如果您有兴趣阅读更多关于我如何使用上述设置的信息,请查看repo:https://github.com/elycruz/sjljs

还有关于该主题的内容的书籍:-Stoyan Stefan ov的“JavaScript模式”。-“Javascript-权威指南”,David Flanagan。-和许多其他人…(搜索le'web)。

您也可以快速测试我在这里谈论的功能:-http://sjljs.elycruz.com/0.5.18/tests/for-browser/(URL中的0.5.18路径也有来自github的源减去node_modules等)。

编码快乐!

这是一个基于公认的答案的实现:

/*** Describes the type of a variable.*/class VariableType{type;name;
/*** Creates a new VariableType.** @param {"undefined" | "null" | "boolean" | "number" | "bigint" | "array" | "string" | "symbol" |*  "function" | "class" | "object"} type the name of the type* @param {null | string} [name = null] the name of the type (the function or class name)* @throws {RangeError} if neither <code>type</code> or <code>name</code> are set. If <code>type</code>* does not have a name (e.g. "number" or "array") but <code>name</code> is set.*/constructor(type, name = null){switch (type){case "undefined":case "null":case "boolean" :case "number" :case "bigint":case "array":case "string":case "symbol":if (name !== null)throw new RangeError(type + " may not have a name");}this.type = type;this.name = name;}
/*** @return {string} the string representation of this object*/toString(){let result;switch (this.type){case "function":case "class":{result = "a ";break;}case "object":{result = "an ";break;}default:return this.type;}result += this.type;if (this.name !== null)result += " named " + this.name;return result;}}
const functionNamePattern = /^function\s+([^(]+)?\(/;const classNamePattern = /^class(\s+[^{]+)?{/;
/*** Returns the type information of a value.** <ul>*   <li>If the input is undefined, returns <code>(type="undefined", name=null)</code>.</li>*   <li>If the input is null, returns <code>(type="null", name=null)</code>.</li>*   <li>If the input is a primitive boolean, returns <code>(type="boolean", name=null)</code>.</li>*   <li>If the input is a primitive number, returns <code>(type="number", name=null)</code>.</li>*   <li>If the input is a primitive or wrapper bigint, returns*   <code>(type="bigint", name=null)</code>.</li>*   <li>If the input is an array, returns <code>(type="array", name=null)</code>.</li>*   <li>If the input is a primitive string, returns <code>(type="string", name=null)</code>.</li>*   <li>If the input is a primitive symbol, returns <code>(type="symbol", null)</code>.</li>*   <li>If the input is a function, returns <code>(type="function", name=the function name)</code>. If the*   input is an arrow or anonymous function, its name is <code>null</code>.</li>*   <li>If the input is a function, returns <code>(type="function", name=the function name)</code>.</li>*   <li>If the input is a class, returns <code>(type="class", name=the name of the class)</code>.*   <li>If the input is an object, returns*   <code>(type="object", name=the name of the object's class)</code>.*   </li>* </ul>** Please note that built-in types (such as <code>Object</code>, <code>String</code> or <code>Number</code>)* may return type <code>function</code> instead of <code>class</code>.** @param {object} value a value* @return {VariableType} <code>value</code>'s type* @see <a href="http://stackoverflow.com/a/332429/14731">http://stackoverflow.com/a/332429/14731</a>* @see isPrimitive*/function getTypeInfo(value){if (value === null)return new VariableType("null");const typeOfValue = typeof (value);const isPrimitive = typeOfValue !== "function" && typeOfValue !== "object";if (isPrimitive)return new VariableType(typeOfValue);const objectToString = Object.prototype.toString.call(value).slice(8, -1);// eslint-disable-next-line @typescript-eslint/ban-typesconst valueToString = value.toString();if (objectToString === "Function"){// A function or a constructorconst indexOfArrow = valueToString.indexOf("=>");const indexOfBody = valueToString.indexOf("{");if (indexOfArrow !== -1 && (indexOfBody === -1 || indexOfArrow < indexOfBody)){// Arrow functionreturn new VariableType("function");}// Anonymous and named functionsconst functionName = functionNamePattern.exec(valueToString);if (functionName !== null && typeof (functionName[1]) !== "undefined"){// Found a named function or class constructorreturn new VariableType("function", functionName[1].trim());}const className = classNamePattern.exec(valueToString);if (className !== null && typeof (className[1]) !== "undefined"){// When running under ES6+return new VariableType("class", className[1].trim());}// Anonymous functionreturn new VariableType("function");}if (objectToString === "Array")return new VariableType("array");
const classInfo = getTypeInfo(value.constructor);return new VariableType("object", classInfo.name);}
   
function UserFunction(){}
function UserClass(){}
let anonymousFunction = function(){};
let arrowFunction = i => i + 1;
console.log("getTypeInfo(undefined): " + getTypeInfo(undefined));console.log("getTypeInfo(null): " + getTypeInfo(null));console.log("getTypeInfo(true): " + getTypeInfo(true));console.log("getTypeInfo(5): " + getTypeInfo(5));console.log("getTypeInfo(\"text\"): " + getTypeInfo("text"));console.log("getTypeInfo(userFunction): " + getTypeInfo(UserFunction));console.log("getTypeInfo(anonymousFunction): " + getTypeInfo(anonymousFunction));console.log("getTypeInfo(arrowFunction): " + getTypeInfo(arrowFunction));console.log("getTypeInfo(userObject): " + getTypeInfo(new UserClass()));console.log("getTypeInfo(nativeObject): " + getTypeInfo(navigator.mediaDevices.getUserMedia));

我们只在没有其他选择时才使用构造函数属性。

说你有var obj;

如果你只是想要obj类型的名称,比如“Object”、“Array”或“String”,你可以使用这个:

Object.prototype.toString.call(obj).split(' ')[1].replace(']', '');

你应该像这样使用somevar.constructor.name

const getVariableType = a => a.constructor.name.toLowerCase();
const d = new Date();const res1 = getVariableType(d); // 'date'const num = 5;const res2 = getVariableType(num); // 'number'const fn = () => {};const res3 = getVariableType(fn); // 'function'
console.log(res1); // 'date'console.log(res2); // 'number'console.log(res3); // 'function'

使用class.name。这也适用于function.name

class TestA {}console.log(TestA.name); // "TestA"
function TestB() {}console.log(TestB.name); // "TestB"

相当简单!

  • 我最喜欢的在JS中获取任何类型的方法
function getType(entity){var x = Object.prototype.toString.call(entity)return x.split(" ")[1].split(']')[0].toLowerCase()}
  • 我最喜欢的检查JS中任何内容类型的方法
function checkType(entity, type){return getType(entity) === type}

对于那些阅读本文并想要一个效果相当好且经过测试的简单解决方案的人:

const getTypeName = (thing) => {const name = typeof thingif (name !== 'object') return nameif (thing instanceof Error) return 'error'if (!thing) return 'null'return ({}).toString.call(thing).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}

要深入了解为什么这是有效的,请查看Array.isArray()的PolyFill留档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray#polyfill