4

I need to check whether a class definition provides either via inheritance or not, a specific method. Do I need to travel the prototype chain to accomplish this?

function TestClass(config){
    //NOTE: cannot instantiate class because if config not valid Error is thrown
}
TestClass.prototype.sampleMethod = function(){};

function isDefined(klass){
      console.log(typeof klass.sampleMethod); //'undefined'
      console.log('sampleMethod' in klass); //false
      console.log(klass['sampleMethod']); //undefined

      console.log(typeof klass.prototype.sampleMethod); //'function' ...inheritance?
}

isDefined(TestClass);

4 Answers 4

1

I think the problem might be that you cannot detect if a class implements something directly without looking at an instance of the class, unless you specifically assign an instance of it to the prototype of a new class for checking. Remember that when the prototype of your class is given the property sampleMethod it is an instance object that represents the prototype, not a class. In fact, classes don't really exist like that in JavaScript.

function TestClass(config){}
TestClass.prototype.sampleMethod = function(){};

function isDefined(klass){
  var holder, _defined = false;
  try{
    holder = new klass({});
    _defined = typeof holder.sampleMethod !== 'undefined'; // does the prototype lookup for you
  }catch(e){
    console.log('Error loading class for reasons other than invalid method.', e)
  }finally{
    return _defined;
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Yes, you need to check the prototype chain.

function TestClass(config){}
TestClass.prototype.sampleMethod = function(){};

function TestClass2() {}
TestClass2.prototype = TestClass;

function isDefined(obj, method) {
    if (obj.prototype !== undefined) {
        var methodInPrototype = (method in obj.prototype);
        console.log("Is " + method + " in prototype of " + obj + ": " + methodInPrototype);
        if (methodInPrototype) {
                return true;
        } else {
            isDefined(obj.prototype, method);
        }
    }
    return false;
}

isDefined(TestClass, "sampleMethod");
isDefined(TestClass2, "sampleMethod");
isDefined(TestClass2, "sampleMethod2");

Prints:

// Is sampleMethod in prototype of function TestClass(config) {}: true
// Is sampleMethod in prototype of function TestClass2() {}: false
// Is sampleMethod in prototype of function TestClass(config) {}: true
// Is sampleMethod2 in prototype of function TestClass2() {}: false
// Is sampleMethod2 in prototype of function TestClass(config) {}: false

1 Comment

You'd also want to do some check to see if method was truly a function and not just a variable, ala (typeof method === 'function')
0

Is this what you're going for?

function TestClass(config) {}
TestClass.prototype.sampleMethod = function() {};

function isDefined(klass, method) {
    return (klass && method ?
    function() {
        return !!klass.prototype[method];
    }() : false);
}

Example of what this does: http://fiddle.jshell.net/Shaz/2kL9A/

3 Comments

Kinda, it would not detect if its inherited: function TestClass2(){} TestClass2.prototype = TestClass; isDefined(TestClass2, 'sampleMethod') I was wondering if there is a shortcut to running your code w/o walking the prototype chain
You can't reliably "walk the prototype chain" as you may not be able to reference all the [[prototype]] objects on it. Just create an instance and see if it has the method.
why is it that the prototype chain cannot be traversed like sonicwizard example?
0

I don't see why you'd test a constructor, I'd just test an object directly to see if it had a particular method.

Anyhow, Gabriel is pretty close, but I'd do it a little differently:

function MyConstructor(){}
MyConstructor.prototype.sampleMethod = function(){};

// Return true if instances of constructor have method
// Return false if they don't
// Return undefined if new constructor() fails 
function isDefined(constructor, method){
  var temp, defined;
  try {
    temp = new constructor();
    defined = !!(typeof temp[method] == 'function');
  } catch(e) {
    // calling - new constructor - failed
  }
  return defined;
}

var foo;

alert(
  isDefined(MyConstructor, 'sampleMethod')             // Method on MyConstructor.prototype
  + '\n' + isDefined(MyConstructor, 'undefinedMethod') // Not defined
  + '\n' + isDefined(MyConstructor, 'toString')        // Method on Object.prototype
  + '\n' + isDefined(foo, 'foo')                       // foo is not a constructor
);

Of course the above is only suitable for classic prototype inheritance via [[prototype]], something else is required where the module pattern or similar is used (i.e. "inhertiance" using closures).

1 Comment

The constructor could take parameters and throw an exception on invalid inputs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.