How to get a JavaScript object's class?

2018-12-31 21:50发布

问题:

I created a JavaScript object, but how I can determine the class of that object?

I want something similar to Java\'s .getClass() method.

回答1:

There\'s no exact counterpart to Java\'s getClass() in JavaScript. Mostly that\'s due to JavaScript being a prototype-based language, as opposed to Java being a class-based one.

Depending on what you need getClass() for, there are several options in JavaScript:

  • typeof
  • instanceof
  • obj.constructor
  • func.prototype, proto.isPrototypeOf

A few examples:

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

Note: if you are compiling your code with Uglify it will change non-global class names. To prevent this, Uglify has a --mangle param that you can set to false is using gulp or grunt.



回答2:

obj.constructor.name

works in most cases in modern browsers, despite Function.name not being officially added to the standard until ES6. If the object is instantiated with var obj = new MyClass(), it will return \"MyClass\" as a string.

It will return \"Number\" for numbers, \"Array\" for arrays and \"Function\" for functions, etc. It seems to be quite reliable. The only cases where it fails are if an object is created without a prototype, via Object.create( null ), or the object was instantiated from an anonymously-defined (unnamed) function.

Arguably, obj.constructor.name is much more intuitive than typeof, and could be encapsulated in a function to handle the odd case where constructor isn\'t defined (and to handle null references).

Note: Another advantage to this method is it works intuitively across DOM boundaries versus comparing the constructor objects directly or using instanceOf. The reason that doesn\'t work as you might expect is there are actually different instances of the constructor function on each DOM, thus doing an object comparison on their constructors won\'t work.

Note 2: Oddly enough, this method appears to return the name of the base-most function used in a prototype chain, which is unfortunately not intuitive. For example if B derives prototypically from A and you create a new instance of B, b, b.constructor.name returns \"A\"! So that feels totally backwards. It does work fine for single-level prototypes and all primitives, however.



回答3:

This function returns either \"undefined\", \"null\", or the \"class\" in [object class] from Object.prototype.toString.call(someObject).

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

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


回答4:

To get the \"pseudo class\", you can get the constructor function, by

obj.constructor

assuming the constructor is set correctly when you do the inheritance -- which is by something like:

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

and these two lines, together with:

var woofie = new Dog()

will make woofie.constructor point to Dog. Note that Dog is a constructor function, and is a Function object. But you can do if (woofie.constructor === Dog) { ... }.

If you want to get the class name as a string, I found the following working well:

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

It gets to the constructor function, converts it to string, and extracts the name of the constructor function.

Note that obj.constructor.name could have worked well, but it is not standard. It is on Chrome and Firefox, but not on IE, including IE 9 or IE 10 RTM.



回答5:

You can get a reference to the constructor function which created the object by using the constructor property:

function MyObject(){
}

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

If you need to confirm the type of an object at runtime you can use the instanceof operator:

obj instanceof MyObject // true


回答6:

In keeping with its unbroken record of backwards-compatibility, ECMAScript 6, JavaScript still doesn\'t have a class type (though not everyone understands this). It does have a class keyword as part of its class syntax for creating prototypes—but still no thing called class. JavaScript is not now and has never been a classical OOP language. Speaking of JS in terms of class is only either misleading or a sign of not yet grokking prototypical inheritance (just keeping it real).

That means this.constructor is still a great way to get a reference to the constructor function. And this.constructor.prototype is the way to access the prototype itself. Since this isn\'t Java, it\'s not a class. It\'s the prototype object your instance was instantiated from. Here is an example using the ES6 syntactic sugar for creating a prototype chain:

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)

This is what that outputs using 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\'

There you have it! In 2016, there\'s a class keyword in JavaScript, but still no class type. this.constructor is the best way to get the constructor function, this.constructor.prototype the best way to get access to the prototype itself.



回答7:

i had a situation to work generic now and used this:

class Test {
  // your class definition
}

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

console.log(nameByType(Test));

thats the only way i found to get the class name by type input if you don\'t have a instance of an object.

(written in ES2017)

dot notation also works fine

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


回答8:

I find object.constructor.toString() return [object objectClass] in IE ,rather than function objectClass () {} returned in chome. So,I think the code in http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects may not work well in IE.And I fixed the code as follows:

code:

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


回答9:

For Javascript Classes in ES6 you can use object.constructor. In the example class below the getClass() method returns the ES6 class as you would expect:

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!\"

If you instantiate the class from the getClass method make sure you wrap it in brackets e.g. ruffles = new ( fluffy.getClass() )( args... );



回答10:

In javascript, there are no classes, but I think that you want the constructor name and obj.constructor.toString() will tell you what you need.



回答11:

Agree with dfa, that\'s why i consider the prototye as the class when no named class found

Here is an upgraded function of the one posted by Eli Grey, to match my way of mind

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 Objects
            if(obj instanceof Array)return \"Array\";// Array prototype is very sneaky
            return \"Object\";
        }
    }
    return res;
}


回答12:

Javascript is a class-less languages: there are no classes that defines the behaviour of a class statically as in Java. JavaScript uses prototypes instead of classes for defining object properties, including methods, and inheritance. It is possible to simulate many class-based features with prototypes in JavaScript.



回答13:

Here\'s a implementation of getClass() and getInstance()

You are able to get a reference for an Object\'s class using window.

From an instance context:

function A() {
    this.getClass = function() {
        return window[this.constructor.name];
    }

    this.getNewInstance = function() {
        return new window[this.constructor.name];
    }
}

var a = new A();
console.log(a.getClass());  //  function A { // etc... }

// you can even:
var b = new a.getClass();
b instanceof A; // true

From static context:

function B() {};

B.getClass = function() {
    return window[this.name];
}

B.getInstance() {
    return new window[this.name];
}


回答14:

Question seems already answered but the OP wants to access the class of and object, just like we do in Java and the selected answer is not enough (imho).

With the following explanation, we can get a class of an object(it\'s actually called prototype in javascript).

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

You can add a property like this:

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

But .last property will only be available to \'arr\' object which is instantiated from Array prototype. So, in order to have the .last property to be available for all objects instantiated from Array prototype, we have to define the .last property for Array prototype:

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

The problem here is, you have to know which object type (prototype) the \'arr\' and \'arr2\' variables belongs to! In other words, if you don\'t know class type (prototype) of the \'arr\' object, then you won\'t be able to define a property for them. In the above example, we know arr is instance of the Array object, that\'s why we used Array.prototype to define a property for Array. But what if we didn\'t know the class(prototype) of the \'arr\'?

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

As you can see, without knowing that \'arr\' is an Array, we can add a new property just bu referring the class of the \'arr\' by using \'arr.__proto__\'.

We accessed the prototype of the \'arr\' without knowing that it\'s an instance of Array and I think that\'s what OP asked.