tags:

views:

16633

answers:

7

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

+44  A: 

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] : "";
};

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.

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

Using the constructor property...

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

Caveats

An example where it isn't as obvious is where you use prototypical inheritance:

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

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

var f = new b(); // create 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.


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


Using the name property of the constructor property...

Does NOT work in IE

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.


Caveats for all...

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.

NOTE:

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. :)

Jason Bunting
What a thorough answer!
Joshua Carmody
Well, I figured I might as well - the point of Stack Overflow is to be a bit like a wiki, and this is much more in line with that intent, I think. Regardless, I just wanted to be somewhat thorough.
Jason Bunting
Re-iterating an answer below --- your extension to the Object prototype does not work in IE8 - does anyone know what would work in IE8?
Adam
@Adam - well, I am going to have to disagree with you because I _just_ tested it in IE 8, because of your comment, and it works fine for me. Not sure what you are doing wrong, but it works.
Jason Bunting
Browser is in quirks mode, that may explain it - do you have a DTD for the HTML page you are testing with?
Adam
+1  A: 

You can use the instanceof operator to see if an object is an instance of another, but since there are no classes, you can't get a class name.

Greg
+7  A: 

Jason Bunting's answer gave me enough of a clue to find what I needed:

<<Object instance>>.constructor.name

So, for example, in the following piece of code:

function MyObject() {}
var myInstance = new MyObject();

myInstance.constructor.name would return "MyObject".

Ewen Cartwright
For completeness, it might be worth mentioning that using constructor.name only works if you used a named function as the constructor as opposed to an anonymous function assigned to a variable.
Matthew Crumley
For completeness, it might worth mentioning that it doesn't work in IE browsers --- they do not support the "name" attribute on functions.
Eugene Lazutkin
@Eugene - I forgot about that... I guess I've spent too much time doing javascript outside browsers.
Matthew Crumley
who develops in IE anyways...
Nicky De Maeyer
+1  A: 

The closest you can get is typeof, but it only returns "object" for any sort of custom type. For those, see Jason Bunting.

Edit, Jason's deleted his post for some reason, so just use Object's constructor property.

sblundy
Yeah, sorry - I deleted it because I figured instanceof() was a better way to do things, but I just undeleted it so that it can serve as a reference.
Jason Bunting
Less than perfect answers are still useful, if only to others to come to the question later because they have a similar problem. So you really shouldn't delete them. Save deletes for wrong answers.
sblundy
Yeah, I know - you are preaching to the choir, I have said the exact same thing to others. Living those things we know to be true is often harder than it looks. :)
Jason Bunting
A: 

You can use the "instanceof" operator to determine if an object is an instance of a certain class or not. If you do not know the name of an object's type, you can use its constructor property. The constructor property of objects, is a reference to the function that is used to initialize them. Example:

function Circle (x,y,radius) {
    this._x = x;
    this._y = y;
    this._radius = raduius;
}
var c1 = new Circle(10,20,5);

Now c1.constructor is a reference to the Circle() function. You can alsow use the typeof operator, but the typeof operator shows limited information. One solution is to use the toString() method of the Object global object. For example if you have an object, say myObject, you can use the toString() method of the global Object to determine the type of the class of myObject. Use this:

Object.prototype.toString.apply(myObject);
farzad
Johnny-come-lately...Why are you merely re-hashing what others have already said? Your answer doesn't really add anything to this page other than clutter.
Jason Bunting
Jason, he is actually right. See my reply (answer).
Christian Sciberras
A: 

this.constructor is not a valid object in IE8, so every implementation like Object.prototype.getName is not valid.

Well, that's strange, because my Object.prototype.getName() _does_ work in IE 8 - as well as IE 7. Burden of proof is on you, provide some example code showing it doesn't work, because I just tested it again and it worked a treat.
Jason Bunting
+1  A: 

DO NOT USE THE CONSTRUCTOR PROPERTY.

Read THIS first.

The correct code is:

function get_type(thing){
    if(thing===null)return "[object Null]"; // special case
    return Object.prototype.toString.call(thing);
}

// example results:
get_type(null)                    - [object Null]
get_type(window)                  - [object Window]
get_type([])                      - [object Array]
get_type(['1'])                   - [object Array]
get_type({})                      - [object Object]
get_type(document)                - [object HTMLDocument]
get_type(document.getElementById) - [object Function]

NB: According to specs, this function is the most reliable between different browsers.

Christian Sciberras