Reputation: 555
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);
Upvotes: 4
Views: 589
Reputation: 147383
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).
Upvotes: 0
Reputation: 140
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
Upvotes: 0
Reputation: 18780
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;
}
}
Upvotes: 1
Reputation: 15867
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/
Upvotes: 0