获取对象类型的名称

2022-08-29 22:04:31

有没有一个JavaScript等同于Java的?class.getName()


答案 1

有没有一个JavaScript等同于Java的?class.getName()

不可以

ES2015 更新类 Foo {} 的名称是 Foo.name。的类的名称(无论 的类型如何)都是 。ES2015环境中的内置构造函数具有正确的属性;例如是 。thingthingthing.constructor.namename(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

每个属性都有一个值,但根据它的构造方式以及您希望对该值执行的操作,它可能有用,也可能没有用。objectconstructorobject

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

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

因此,这足以满足大多数需求。可是。。。

警告

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

这种模式虽然被打破了,但很常见:

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

Objectsvia 构造将具有指向 的属性,而不是 。因此,我们从一开始就堕落了。你根本无法信任一个你无法控制的代码库。new ThingyconstructorObjectThingyconstructor

多重继承

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

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

因此,如果您的测试具有不同的集合作为其 .在本次讨论的范围之外,还有一些方法可以解决这个问题。objectobjectprototype

该物业还有其他用途,其中一些很有趣,有些则不那么有趣;现在,我们不会深入研究这些用途,因为它与此讨论无关。constructor

将不工作跨框架和跨窗口

当您想要检查来自不同对象的对象类型(例如 iframe 或弹出窗口)时,使用 for type 检查将中断。这是因为每个“窗口”中都有每个核心类型的不同版本,即.constructorwindowconstructor

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

使用运算符...instanceof

运算符也是测试类型的一种干净方法,但也有其自身的潜在问题,就像属性一样。instanceofobjectconstructor

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

但不适用于文本值(因为文本不是instanceofObjects)

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

文本需要包装在 中才能工作,例如Objectinstanceof

new Number(3) instanceof Number // true

该检查对文本工作正常,因为方法调用隐式地将文本包装在它们各自的对象类型中.constructor.

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

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

将不工作跨框架和跨窗口

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


使用属性的属性...nameconstructor

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

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

在 <IE9 中不起作用

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

对于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.toString

事实证明,正如本文所详述的那样,您可以使用 - 的低级和泛型实现 - 来获取所有内置类型的类型Object.prototype.toStringtoString

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);
}

以删除 cruft 并仅获取类型名称

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 inheritance
function 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 variable
var 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 syntax
obj = { foo : 1 };
(obj instanceof Object);            // true
(obj.constructor == Object);        // true
(obj.constructor.name == "Object"); // true

虽然这组示例中并不存在所有排列,但希望有足够的排列来为您提供有关根据您的需求可能变得混乱的想法。不要假设任何事情,如果你不确切地理解你所追求的是什么,你最终可能会因为缺乏对微妙之处的摸索而导致代码中断,而你并不期望它。

注意:

对运算符的讨论似乎是一个明显的遗漏,但它在帮助确定是否是给定类型方面确实没有用处,因为它非常简单。了解哪里有用很重要,但我目前并不觉得它与这个讨论非常相关。不过,我的思想对改变持开放态度。:)typeofobjecttypeof


答案 2

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

<<Object instance>>.constructor.name

因此,例如,在下面的代码段中:

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

myInstance.constructor.name会回来。"MyObject"