如何获取JavaScript对象的类?

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

我想要类似于Java的.getClass()方法的东西。

951554 次浏览

在JavaScript中没有与Java的getClass()完全对应的东西。主要是因为JavaScript是基于原型的语言,而Java是基于类

根据您需要getClass()的目的,JavaScript中有几个选项:

举几个例子:

function Foo() {}var foo = new Foo();
typeof Foo;             // == "function"typeof foo;             // == "object"
foo instanceof Foo;     // == truefoo.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参数,您可以在使用吞咽咕噜时将其设置为false。

JavaScript是一种无类语言:没有像Java那样静态定义类行为的类。JavaScript使用原型而不是类来定义对象属性,包括方法和继承。使用JavaScript中的原型可以模拟许多基于类的特性。

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

function MyObject(){}
var obj = new MyObject();obj.constructor; // MyObject

如果您需要在运行时确认对象的类型,您可以使用instance of运算符:

obj instanceof MyObject // true

在javascript中,没有类,但我认为您需要构造函数名称,obj.constructor.toString()会告诉您需要什么。

这个getNativeClass()函数对于未定义的值返回"undefined",对于null返回"null"
对于所有其他值,CLASSNAME-part是从[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...
obj.constructor.name

Function.name在ES6中被正式添加到标准中,使其成为一种标准兼容的获取JavaScript对象的“类”作为字符串的方法。如果对象用var obj = new MyClass()实例化,它将返回“MyClass”。

它将返回数字的“数字”,数组的“数组”和函数的“函数”等。它通常按预期行事。它失败的唯一情况是,如果通过Object.create( null )在没有原型的情况下创建对象,或者该对象是从匿名定义(未命名)函数实例化的。

另请注意,如果您正在缩小代码,与硬编码类型字符串进行比较是不安全的。例如,不是检查obj.constructor.name == "MyType",而是检查obj.constructor.name == MyType.name。或者只是比较构造函数本身,但是这不会跨越DOM边界,因为每个DOM上有不同的构造函数实例,因此对它们的构造函数进行对象比较是行不通的。

要获取“伪类”,您可以通过以下方式获取构造函数

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。

我发现object.constructor.toString()在IE中返回[object objectClass],而不是function objectClass () {}在chome中返回。所以,我认为http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects中的代码在IE中可能无法正常工作。

代码:

var getObjectClass = function (obj) {if (obj && obj.constructor && obj.constructor.toString()) {            
/**  for browsers which have name property in the constructor*  of the object,such as chrome*/if(obj.constructor.name) {return obj.constructor.name;}var str = obj.constructor.toString();/** executed if the return of object.constructor.toString() is* "[object objectClass]"*/                 
if(str.charAt(0) == '['){var arr = str.match(/\[\w+\s*(\w+)\]/);} else {/** executed if the return of object.constructor.toString() is* "function objectClass () {}"* for IE Firefox*/var arr = str.match(/function\s*(\w+)/);}if (arr && arr.length == 2) {return arr[1];}}return undefined;};    

同意dfa,这就是为什么当没有找到命名类时,我认为原型是类

这是Eli Grey发布的一个升级功能,以匹配我的思维方式

function what(obj){if(typeof(obj)==="undefined")return "undefined";if(obj===null)return "Null";var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];if(res==="Object"){res = obj.constructor.name;if(typeof(res)!='string' || res.length==0){if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objectsif(obj instanceof Array)return "Array";// Array prototype is very sneakyreturn "Object";}}return res;}

这是getClass()getInstance()的实现

您可以使用this.constructor获取Object类的引用。

从实例上下文:

function A() {this.getClass = function() {return this.constructor;}
this.getNewInstance = function() {return new this.constructor;}}
var a = new A();console.log(a.getClass());  //  function A { // etc... }
// you can even:var b = new (a.getClass());console.log(b instanceof A); // truevar c = a.getNewInstance();console.log(c instanceof A); // true

从静态上下文:

function A() {};
A.getClass = function() {return this;}
A.getInstance() {return new this;}

对于ES6中的Javascript类,您可以使用object.constructor。在下面的示例类中,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... );

为了保持其向后兼容的完整记录,ECMAScript 6,JavaScript仍然没有class类型(尽管不是每个人都理解这一点)。它确实有一个class关键字作为创建原型的class语法的一部分-但是还是没有所谓的阶级。JavaScript不是现在,而是从来都不是经典的OOP语言。从类的角度谈论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是访问原型本身的最佳方式。

问题似乎已经回答了,但是OP想要访问类和对象,就像我们在Java中所做的那样,选择的答案是不够的(imho)。

通过下面的解释,我们可以得到一个对象的类(它实际上在JavaScript中被称为原型)。

var arr = new Array('red', 'green', 'blue');var arr2 = new Array('white', 'black', 'orange');

你可以像这样添加一个属性:

Object.defineProperty(arr,'last', {get: function(){return this[this.length -1];}});console.log(arr.last) // blue

但是.last属性只能用于从Array原型实例化的“arr”对象。因此,为了让.last属性可用于从Array原型实例化的所有对象,我们必须为Array原型定义.last属性:

Object.defineProperty(Array.prototype,'last', {get: function(){return this[this.length -1];}});console.log(arr.last) // blueconsole.log(arr2.last) // orange

这里的问题是,你必须知道'arr'和'arr2'变量属于哪个对象类型(原型)!换句话说,如果你不知道'arr'对象的类类型(原型),那么你将无法为它们定义一个属性。在上面的例子中,我们知道arr是Array对象的实例,这就是为什么我们使用Array.prototype来为Array定义一个属性。但是如果我们不知道'arr'的类(原型)呢?

Object.defineProperty(arr.__proto__,'last2', {get: function(){return this[this.length -1];}});console.log(arr.last) // blueconsole.log(arr2.last) // orange

如您所见,在不知道“arr”是一个数组的情况下,我们可以添加一个新属性,只需使用“arr.__proto__”引用“arr”的类。

我们在不知道它是Array的实例的情况下访问了arr的原型,我认为这就是OP所问的。

我现在有一个通用工作的情况,并使用了这个:

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"

我建议使用Object.prototype.constructor.name

Object.defineProperty(Object.prototype, "getClass", {value: function() {return this.constructor.name;}});
var x = new DOMParser();console.log(x.getClass()); // `DOMParser'
var y = new Error("");console.log(y.getClass()); // `Error'

你也可以这样做

 class Hello {constructor(){}}    
function isClass (func) {return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))}    
console.log(isClass(Hello))

这将告诉您输入是否是类

如果您不仅需要GET类,还需要从只有一个实例扩展它,请编写:

让我们有

 class A{constructor(name){this.name = name}};
const a1 = new A('hello a1');

因此,要扩展仅具有实例的A,请使用:

const a2 = new (Object.getPrototypeOf(a1)).constructor('hello from a2')// the analog of const a2 = new A()
console.log(a2.name)//'hello from a2'

有另一种技术来识别你的类你可以像下面这样将ref存储到你的类中。

class MyClass {static myStaticProperty = 'default';constructor() {this.__class__ = new.target;this.showStaticProperty = function() {console.log(this.__class__.myStaticProperty);}}}
class MyChildClass extends MyClass {static myStaticProperty = 'custom';}
let myClass = new MyClass();let child = new MyChildClass();
myClass.showStaticProperty(); // defaultchild.showStaticProperty(); // custom
myClass.__class__ === MyClass; // truechild.__class__ === MyClass; // falsechild.__class__ === MyChildClass; // true

我们可以通过执行instance.constructor.name来读取实例的Class名称,如下例所示:

class Person {type = "developer";}let p = new Person();
p.constructor.name // Person

getClass()函数使用constructor.prototype.name

我找到了一种访问class的方法,它比上面的一些解决方案要干净得多;在这里。

function getClass(obj) {
// if the type is not an object return the typeif((let type = typeof obj) !== 'object') return type;    
//otherwise, access the class using obj.constructor.nameelse return obj.constructor.name;}

它是如何运作的

构造函数有一个名为name访问的属性,它将为您提供类名。

更干净的代码版本:

function getClass(obj) {
// if the type is not an object return the typelet type = typeof objif((type !== 'object')) {return type;} else { //otherwise, access the class using obj.constructor.namereturn obj.constructor.name;}}