简体   繁体   中英

How can I check whether a method is defined in a JavaScript class

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

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

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/

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

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 (ie "inhertiance" using closures).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM