views:

89

answers:

3

Hi.

Say I have an "abstract class" like this:

function AbstractClass() {    
  this.getImplementingName = function() {
      return /* how do I get this? */;
  }    
}

and an implementation like

function ImplmentingClass() {
}
ImplmentingClass.prototype = new AbstractClass();

var impl = new ImplmentingClass()
var name = impl.getImplementingName();

/* how do I get... (name == 'ImplementingClass') */

thanks

+1  A: 

Check the .constructor property (and or the instanceof operator)

scunliffe
+1  A: 

I don't think there's a direct way of doing what you are trying to accomplish, but this is how I would approach it. I would override toString() in the implementingClass.

function AbstractClass() {
    this.getImplementingName = function() {
     return this.toString();
    }
}
function ImplmentingClass() {
  this.toString = function(){return "ImplementingClass";}
}
ImplmentingClass.prototype = new AbstractClass();


var impl = new ImplmentingClass()
var name = impl.getImplementingName(); /* name equals "ImplementingClass" */
Jose Basilio
+2  A: 

You see, both - AbstractClass and ImplementingClass are simply functions. Functions in Javascript (or more precisely - in standard ECMAScript-262 3rd ed.) do not have any kind of string-like "name" value associated with them. AbstractClass and ImplementingClass in this case are function Identifiers; These Identifiers are merely part of production of every function declaration (but not always of function expression, which is why function expressions can be anonymous).

In some of the ES3 implementations, the value of this Identifier is being automatically assigned to a function object's name property, during function creation. This is, of course, a non-standard extension, currently implemented by some of the Gecko and WebKit-based browsers. It's also being discussed by ES committee and might make its way into future versions of ECMAScript.

(function foo(){}).name; // "foo" in Safari 4.x and FF 3.x

There's also toString method, available on all Function objects via Function.prototype.toString:

String(function foo(){}); // "function foo() {}"

Unfortunately, ECMAScript specifies this method to return implementation dependent function representation and so relying on parsing this value is rather fragile. Such parsing is called function decompilation, and is usually recommended against for exactly this reason of it being non-standard and quirky (I wrote about some of these quirks couple of times). Note that next version of ECMAScript (ES5, currently draft) doesn't change these rules either.

Your best bet is to either assign property manually or employ some kind of a factory-like helper. E.g.:

function initFn(name, fn) {
  fn.name = name;
  return fn;
}
// and then
var AbstractClass = initFn('AbstractClass', function(){
  // ...
});

// or directly

function foo(){}
foo.name = 'foo';

Note the repetition here ("AbstractClass" string), which, unfortunately, can only be avoided by using either eval or Function constructor (both - less than ideal solutions).

If you need instance object to know "name" of its constructor, it should be trivial to implement similar "piggybacking" with some kind of abstraction.

kangax