如何获取JavaScript对象的类?

1051

我创建了一个JavaScript对象,但是我该如何确定那个对象的类?

我想要类似于Java中 .getClass() 方法的功能。


14
我创建了一个类似于这样的 Person 对象:var p = new Person();如何使用 "p" 来获取类名:"Person"。 - DNB5brims
8
Duplicate - Casebash
更新:截至ECMAScript 6,JavaScript仍然没有“class”类型。它确实有一个“class”关键字和“class”语法,用于创建原型,其中方法可以更轻松地访问“super”。 - james_womack
Object.className 怎么样? - Paul Basenko
1
@Paul-Basenko: "className"不能告诉你对象的类,但会返回HTML元素的“class”属性内容,该属性是指CSS类。您还要使用“classList”轻松管理它们,但这与OP的问题无关。 - Obsidian
这个回答解决了你的问题吗?获取对象类型的名称 - handle
22个回答

1399

在JavaScript中,没有与Java的getClass()完全对应的方法。这主要是因为JavaScript是一种基于原型的语言,而Java则是一种基于的语言。

根据您需要使用getClass()的情况,在JavaScript中有几个选项:

以下是一些示例:

function Foo() {}
var foo = new Foo();

typeof Foo;             // == "function"
typeof foo;             // == "object"

foo instanceof Foo;     // == true
foo.constructor.name;   // == "Foo"
Foo.name                // == "Foo"    

Foo.prototype.isPrototypeOf(foo);   // == true

Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21);            // == 42

注意:如果您使用Uglify编译代码,则会更改非全局类名。为了防止这种情况发生,Uglify有一个--mangle参数,如果使用gulpgrunt,则可以将其设置为false。

6
这可能应该是 func.prototype(是的,函数是对象,但 prototype 属性只在函数对象上有意义)。 - Miles
5
你可能还想提到 instanceof/isPrototypeOf() 和非标准的 __proto__ - Christoph
15
ES5 还新增了 Object.getPrototypeOf() 方法。 - Christoph
58
警告:如果你的代码被压缩,不要依赖于 constructor.name。函数名称将会任意更改,因此可能无法准确获取。 - igorsantos07
11
至少在2019年,对于“在线Javascript代码压缩器”的前5到10个谷歌搜索结果,都认为construction.name是一个需要忽略/不压缩的标记。此外,大多数(如果不是全部)的压缩软件都提供了例外规则。 - vulcan raven
显示剩余6条评论

434
obj.constructor.name

在现代浏览器中,Function.name是一种可靠的方法。它在ES6标准中正式添加,可以将JavaScript对象的“类”作为字符串返回,符合标准。如果使用var obj = new MyClass()实例化对象,则会返回“MyClass”。

对于数字,它会返回“Number”,对于数组,它会返回“Array”,对于函数等等,它通常表现如预期。唯一失败的情况是如果通过Object.create( null )创建了一个没有原型的对象,或者对象是从匿名定义(无名称)的函数实例化的。

还要注意,如果你正在压缩代码,直接与硬编码的类型字符串进行比较是不安全的。例如,不要检查obj.constructor.name == "MyType",而是检查obj.constructor.name == MyType.name。或者只比较构造函数本身,但这在DOM边界上不起作用,因为每个DOM上都有不同的构造函数实例。


11
Function.name 目前还不是 JavaScript 标准的一部分。它目前在 Chrome 和 Firefox 中得到支持,但在 IE(10)中不受支持。 - Halcyon
Object.create(something).constructor === something.constructor 这个说法并不完全正确。因此,无论是否使用原型,对于所有使用 Object.create 创建的对象,obj.constructor 都是不可靠的。 - user2451227
59
警告:如果你的代码被压缩,不要依赖于constructor.name。函数名称将会任意更改,因此请注意。 - igorsantos07
1
Function.name 是 ES6 的一部分,详情请查看 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/name - Janus Troelsen
我不理解你关于链式原型的注释。 对于我而言,它可以正常工作(在 Firefox 控制台上测试): class A { }; class B extends A { }; b = new B(); b.constructor.name; "B" - Wojciech Kałuski
1
@adalbertpl这与在ES6之前手动链接原型有关。了解constructor.name与ES6中的新类支持一样所表现出的预期行为是很好的。 - devios1

40

这个getNativeClass()函数会对未定义的值返回"undefined",对空值返回"null"
对于所有其他值,CLASSNAME部分是从[object CLASSNAME]中提取的,这是使用Object.prototype.toString.call(value)的结果。

getAnyClass()与getNativeClass()的行为相同,但还支持自定义构造函数。

function getNativeClass(obj) {
  if (typeof obj === "undefined") return "undefined";
  if (obj === null) return "null";
  return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}

function getAnyClass(obj) {
  if (typeof obj === "undefined") return "undefined";
  if (obj === null) return "null";
  return obj.constructor.name;
}

getClass("")   === "String";
getClass(true) === "Boolean";
getClass(0)    === "Number";
getClass([])   === "Array";
getClass({})   === "Object";
getClass(null) === "null";

getAnyClass(new (function Foo(){})) === "Foo";
getAnyClass(new class Foo{}) === "Foo";

// etc...

1
Object.prototype.getClass = function(){ 使用'this'代替obj会更好。 - SparK
2
当然,如果只有对象才有getClass方法,那么null和undefined将无法检查。 - SparK
12
这仅适用于本地对象。如果您有某种继承关系,您将始终获得“Object”。 - Halcyon
是的,函数的最后一行应该只是 return obj.constructor.name。这样可以得到相同的结果,还可以处理非本地对象。 - Steve Bennett

33
我们可以通过这个例子来看如何仅仅使用'instance.constructor.name'就能够读取实例的类名称:
class Person {
  type = "developer";
}
let p = new Person();

p.constructor.name // Person

1
所有的乐趣都会消失,直到你压缩JS并且你的类名现在是n。 对于这种事情,JS真的很糟糕。 - Askdesigners

22

要获取“伪类(pseudo class)”,你可以通过以下方式获取构造函数:

obj.constructor

假设您在继承过程中已正确设置了constructor,方式类似于:

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

而这两行与以下代码一起:

var woofie = new Dog()

将使woofie.constructor指向Dog。请注意,Dog是一个构造函数,也是一个Function对象。但您可以使用if (woofie.constructor === Dog) { ... }

如果您想将类名作为字符串获取,我发现以下内容非常有效:

http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects

function getObjectClass(obj) {
    if (obj && obj.constructor && obj.constructor.toString) {
        var arr = obj.constructor.toString().match(
            /function\s*(\w+)/);

        if (arr && arr.length == 2) {
            return arr[1];
        }
    }

    return undefined;
}

代码到了构造函数,将其转换为字符串并提取构造函数的名称。

请注意obj.constructor.name可能效果很好,但它不是标准。它在Chrome和Firefox上可用,但在IE上不可用,包括IE 9或IE 10 RTM。


你可以通过Woofie获得积分。 - user1974458

16

通过使用constructor 属性,您可以获取创建对象的构造函数引用:

function MyObject(){
}

var obj = new MyObject();
obj.constructor; // MyObject

如果你需要在运行时确认一个对象的类型,你可以使用instanceof操作符:

obj instanceof MyObject // true

它不是返回构造函数本身吗,就像你可以再次调用它并创建该类型的新对象吗? - SparK
1
@SparK 是的,尽管如此,只要您在相同的DOM上(比较函数对象),仍然可以将其用于比较。但是最好的做法是将构造函数转换为字符串并进行比较,特别是当使用iframes时,它可以跨越DOM边界工作。 - devios1
这个答案返回了“类”(或者至少是一个可以用来创建类实例的对象句柄 - 这与“类”相同)。以上所有答案都返回了字符串,这与“类对象”不同(就像它一样)。 - Mike P.

11

我曾经遇到了需要使用通用方法的情况,然后我使用了这个:

class Test {
  // your class definition
}

nameByType = function(type){
  return type.prototype["constructor"]["name"];
};

console.log(nameByType(Test));

这是我找到的获取输入类型类名的唯一方法,如果你没有对象实例。

(使用ES2017编写)

点表示法也可以正常工作。

console.log(Test.prototype.constructor.name); // returns "Test" 

啊,这就是我在寻找的东西。如果它没有被实例化,你必须使用“prototype”来获取类名。非常感谢! - Artokun

9
为了保持其向后兼容的记录,ECMAScript 6中JavaScript仍然没有“class”类型(尽管并非每个人都明白这一点)。它确实有一个“class”关键字作为创建原型的“class”语法的一部分,但仍然没有称之为“class”的东西。JavaScript从未是一种经典的面向对象编程语言。用类来描述JS只会误导或者表明还没有完全理解原型继承(说实话)。
这意味着“this.constructor”仍然是获取对“constructor”函数引用的好方法。而“this.constructor.prototype”则是访问原型本身的方式。由于这不是Java,所以不是一个类。它是您的实例从中实例化的原型对象。以下是使用ES6语法糖创建原型链的示例:
class Foo {
  get foo () {
    console.info(this.constructor, this.constructor.name)
    return 'foo'
  }
}

class Bar extends Foo {
  get foo () {
    console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
    console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))

    return `${super.foo} + bar`
  }
}

const bar = new Bar()
console.dir(bar.foo)

这是使用babel-node输出的结果:
> $ babel-node ./foo.js                                                                                                                   ⬡ 6.2.0 [±master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'

就是这样!在2016年,JavaScript中有一个class关键词,但仍然没有类类型。this.constructor是获取构造函数的最佳方式,this.constructor.prototype是访问原型本身的最佳方式。


6

在ES6中,您可以使用object.constructor来处理Javascript类。在下面的示例类中,getClass()方法返回预期的ES6类:

var Cat = class {

    meow() {

        console.log("meow!");

    }

    getClass() {

        return this.constructor;

    }

}

var fluffy = new Cat();

...

var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();

ruffles.meow();    // "meow!"

如果您从getClass方法实例化类,请确保将其包装在括号中,例如:ruffles = new ( fluffy.getClass() )( args... );。该代码涉及IT技术方面的内容。

5

不要使用o.constructor,因为它可能会被对象内容更改。相反,使用Object.getPrototypeOf()?.constructor

const fakedArray = JSON.parse('{ "constructor": { "name": "Array" } }');

// returns 'Array', which is faked.
fakedArray.constructor.name;

// returns 'Object' as expected
Object.getPrototypeOf(fakedArray)?.constructor?.name;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接