获取对象类型的名称

问题描述:

是否存在Java等效的Java class.getName()

Is there a JavaScript equivalent of Java's class.getName()?


是否存在Java的等效Java class.getName()

No.

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

ES2015 Update: the name of class Foo {} is Foo.name. The name of thing's class, regardless of thing's type, is thing.constructor.name. Builtin constructors in an ES2015 environment have the correct name property; for instance (2).constructor.name is "Number".

但是这里有各种各样的黑客攻击:

But here are various hacks that all fall down in one way or another:

这是一个黑客攻击这将做你需要的 - 要知道它修改了对象的原型,人们皱眉(通常有充分理由)

Here is a hack that will do what you need - be aware that it modifies the Object's prototype, something people frown upon (usually for good reason)

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

现在,你的所有对象都将拥有函数 getName(),这将返回名称构造函数作为字符串。我在 FF3 IE7 中测试了这个,我不能代表其他实现。

Now, all of your objects will have the function, getName(), that will return the name of the constructor as a string. I have tested this in FF3 and IE7, I can't speak for other implementations.

如果你不想这样做,这里讨论决定的各种方法JavaScript中的g类型...

If you don't want to do that, here is a discussion on the various ways of determining types in JavaScript...

我最近更新了这个更详尽一点,尽管不是那样。更正欢迎...

I recently updated this to be a bit more exhaustive, though it is hardly that. Corrections welcome...

每个对象都有一个构造函数属性的值,但取决于 object 以及您想要对该值执行的操作,它可能有用也可能没用。

Every object has a value for its constructor property, but depending on how that object was constructed as well as what you want to do with that value, it may or may not be useful.

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

Generally speaking, you can use the constructor property to test the type of the object like so:

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

因此,这对大多数需求都有效。那说......

So, that works well enough for most needs. That said...

无法正常运行在很多情况下

Will not work AT ALL in many cases

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

This pattern, though broken, is quite common:

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

对象通过 new Thingy 将有一个构造函数属性,指向 Object ,而不是。所以我们一开始就是正确的;你根本无法信任构造函数在你无法控制的代码库中。

Objects constructed via new Thingy will have a constructor property that points to Object, not Thingy. So we fall right at the outset; you simply cannot trust constructor in a codebase that you don't control.

多重继承

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

An example where it isn't as obvious is using multiple inheritance:

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

事情现在无法正常发挥作用:

Things now don't work as you might expect them to:

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

因此,如果对象,您可能会收到意外结果您的测试有一个不同的对象设置为原型。在本讨论范围之外,有很多方法可以解决这个问题。

So, you might get unexpected results if the object your testing has a different object set as its prototype. There are ways around this outside the scope of this discussion.

构造函数属性有其他用途,有些用途他们有趣,其他人没有那么多;目前我们不会深入研究这些用途,因为它与此讨论无关。

There are other uses for the constructor property, some of them interesting, others not so much; for now we will not delve into those uses since it isn't relevant to this discussion.

跨框架和跨窗口无法工作

当您要检查来自不同的对象类型时,使用 .constructor 进行类型检查会中断code> window 对象,比如iframe或弹出窗口。这是因为每个窗口中每个核心类型构造函数的版本不同,即

Using .constructor for type checking will break when you want to check the type of objects coming from different window objects, say that of an iframe or a popup window. This is because there's a different version of each core type constructor in each `window', i.e.

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






使用 instanceof 运算符...



instanceof 运算符也是一种测试 object 类型的简洁方法,但是它有自己的潜在问题,就像构造函数一样 property。


Using the instanceof operator...

The instanceof operator is a clean way of testing object type as well, but has its own potential issues, just like the constructor property.

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

instanceof 无法正常工作对于文字值(因为文字不是对象

But instanceof fails to work for literal values (because literals are not Objects)

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

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

The literals need to be wrapped in an Object in order for instanceof to work, for example

new Number(3) instanceof Number // true

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

The .constructor check works fine for literals because the . method invocation implicitly wraps the literals in their respective object type

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

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

Why two dots for the 3? Because Javascript interprets the first dot as a decimal point ;)

instanceof 也不能在不同的窗口中工作,原因与构造函数属性检查的原因相同。

instanceof also will not work across different windows, for the same reason as the constructor property check.

再次,见上文; 构造函数通常是完全错误和无用的。

Again, see above; it's quite common for constructor to be utterly and completely wrong and useless.

使用 myObjectInstance.constructor.name 将为您提供一个包含构造函数名称的字符串使用的函数,但有关前面提到的构造函数属性的警告。

Using myObjectInstance.constructor.name will give you a string containing the name of the constructor function used, but is subject to the caveats about the constructor property that were mentioned earlier.

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

For IE9 and above, you can monkey-patch in support:

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使用的推荐版本。这一变化的灵感来自评论指出潜在的陷阱在前面的代码中。

Updated version from the article in question. This was added 3 months after the article was published, this is the recommended version to use by the article's author Matthew Scharley. This change was inspired by comments pointing out potential pitfalls in the previous code.

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 的低级和通用实现 - 获取所有内置类型的类型


Using Object.prototype.toString

It turns out, as this post details, you can use Object.prototype.toString - the low level and generic implementation of toString - to get the type for all built-in types

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

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

One could write a short helper function such as

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

删除残骸并获取类型名称

to remove the cruft and get at just the type name

type('abc') // String

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

However, it will return Object for all user-defined types.

所有这些都是一个潜在的问题,这就是对象的问题问题是建立的。以下是构建对象的各种方法以及不同类型检查方法将返回的值:

All of these are subject to one potential problem, and that is the question of how the object in question was constructed. Here are various ways of building objects and the values that the different methods of type checking will return:

// 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

虽然并非所有的排列都出现在这组例子中,但希望有足够的提供根据您的需求,您可以了解有关杂乱的事情。不要假设任何事情,如果你不完全理解你所追求的是什么,你最终可能会因为缺乏细微之处而在你不期望的地方打破代码。

While not all permutations are present in this set of examples, hopefully there are enough to provide you with an idea about how messy things might get depending on your needs. Don't assume anything, if you don't understand exactly what you are after, you may end up with code breaking where you don't expect it to because of a lack of grokking the subtleties.

讨论 typeof 运算符似乎是一个明显的遗漏,但它确实无助于确定对象是否为给定类型,因为它非常简单。了解 typeof 的用途非常重要,但我目前并不认为它与此讨论非常相关。我的思想可以改变。 :)

Discussion of the typeof operator may appear to be a glaring omission, but it really isn't useful in helping to identify whether an object is a given type, since it is very simplistic. Understanding where typeof is useful is important, but I don't currently feel that it is terribly relevant to this discussion. My mind is open to change though. :)