小编典典

获取对象类型的名称

all

有与 Java* 等效的 JavaScript 吗? *class.getName()


阅读 166

收藏
2022-02-25

共1个答案

小编典典

是否有与 Java 等效的 JavaScript class.getName()

没有

ES2015 更新名字class Foo {}Foo.name.
的类的名称thing,不管thing‘ 的类型,是thing.constructor.name。ES2015
环境中的内置构造函数具有正确的name属性;例如(2).constructor.name"Number"


但这里有各种各样的黑客,它们都以一种或另一种方式失败:

这是一个可以满足您需要的 hack - 请注意它会修改对象的原型,这是人们不赞成的(通常是有充分理由的)

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

现在,您的所有对象都将具有函数
getName()它将以字符串形式返回构造函数的名称。我已经在FF3and中对此进行了测试IE7,我不能代表其他实现。

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


我最近将其更新为更加详尽,尽管实际上并非如此。欢迎指正…

使用constructor物业…

每个属性object都有一个值constructor,但取决于它object是如何构造的以及你想用这个值做什么,它可能有用也可能没用。

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

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

因此,这足以满足大多数需求。那就是说…

注意事项

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

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

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

Objects构造 vianew Thingy将有一个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,其中一些很有趣,另一些则不那么有趣;现在我们不会深入研究这些用途,因为它与本次讨论无关。

不能跨框架和跨窗口工作

.constructor当您想要检查来自不同对象的对象类型时,使用类型检查将中断window,例如 iframe
或弹出窗口。这是因为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 // false
true instanceof Boolean // false

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

new Number(3) instanceof Number // true

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

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

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

不能跨框架和跨窗口工作

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


使用该name属性的constructor属性…

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

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

不适用于 <IE9

UsingmyObjectInstance.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.toString

事实证明,正如这篇文章所详述的那样,您可以使用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 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

虽然这组示例中并非所有排列都存在,但希望足以让您了解根据您的需要,事情可能会变得多么混乱。不要假设任何事情,如果您不完全了解您所追求的目标,您可能会因为缺乏对细微之处的了解而导致代码破坏在您不期望的地方。

笔记:

对运算符的讨论typeof可能看起来是一个明显的遗漏,但它对于帮助确定 an
是否object是给定类型确实没有用,因为它非常简单。了解哪里typeof有用很重要,但我目前认为它与本次讨论没有太大关系。不过,我的想法是愿意改变的。:)

2022-02-25