How can I get the names of the methods in a constructor of a class?

class Example {
  constructor(){
    //  get method list ["method1", "method2"]
  }

  method1(){}

  method2(){}
}

Basically, use Object.getOwnPropertyNames() and then check each returned value to see if its of type “function” (making it a method on the object).or not (making it a property).

The object gets created by the constructor, it doesn’t exist beforehand, those methods do not exist unless you instantiate them inside the constructor (which is not generally what you want to do).

3 Likes

But in constructor not outside.

Been playing with that, just to see if it was even possible. Within the constructor? Not so much. Here’s the code I’ve been testing with (or find it on repl):

class Person{
  constructor({name, age, friends}){
    // When we have an object, it has a prototype
    console.log(this.constructor);
    this.name = name;
    this.age = age;
    // WITHIN the class, however, the methods haven't been
    //  wired up yet.
    let myMethods = this.getAllMethods();
    console.log("In the constructor, methods are: ", myMethods);

    /**
     * The following will get me get the class methods within the constructor.
     *   getAllMethods() is a constructor method, so it will run, and it runs it 
     *   on that constructor. Seems hacky to me, but it does work.
     **/
    let myClassMethods = this.constructor.prototype.getAllMethods();
    console.log("And the class methods IN THE CONSTRUCTOR: ", myClassMethods)
  }

  getAllMethods(){
    // First, let's get all property names.
    let myPropertyNames = Object.getOwnPropertyNames(this);
    // And only keep the functions
    return myPropertyNames.filter(property => {
      // This wil return true for functions, thus
      //  telling filter to keep this one.
      return typeof(this[property]) === 'function'
    })
  }

  foo(){
    return "Foo";

  }
  setName(name){
    //...
  }
}

// From OUTSIDE, I can see the methods of a class
console.log(Object.getOwnPropertyNames(Person.prototype));

// I can create an instance, but the class methods are not his own:
let bill = new Person({name: "Bill", age: 39})
// We'll add a method, just to show one.
bill.getName = function(){this.name}; 

// Object.getOwnPropertyNames doesn't return class methods/properties
console.log("Bill's methods: ",bill.getAllMethods());

// But I can also use my getAllMethods on the Person class
console.log("Person's methods: ",Person.prototype.getAllMethods()  )

// We can also get this from bill himself:
console.log("Bill's constructor(class) methods:", bill.constructor.prototype.getAllMethods() );

Within the constructor, Object.getOwnPropertyNames() returns an empty list – because we’re on the object being constructed, not the class. After the object has been created using that class, we can get both our object instance (above, bill) as well as our class (above, Person).

But within the constructor, those methods don’t exist. I think. Not without some hacky code and bad juju, anyway.

EDIT: I was wrong. Well, no – it still seems really hacky and kind of useless, but we CAN get the class methods within the constructor – by calling Object.getOwnPropertyNames(this.constructor.prototype) or something. I’ve edited the code sample above to show it, using my getAllMethods() to filter out any properties that aren’t methods.

Sigh…

1 Like

@aykutkardas, I’m really curious – I can’t come up with a single reason why, when I’m creating an object from a class, that I’d need to learn the methods of the class. Unless they’re obfuscated, and you want to create some weird getter/setter mechanism, but that seems to me to be just ASKING for trouble.

I was working on a standard method that would make the developer less tired to “bind” the methods to the class.

class Example {
  consturctor(){
    this.method = this.method.bind(this);
  }

 method(){}

 nonStandartBindingMethod = () => {}
}

Ah. Gotcha. Clever, really, but I think that may break elsewhere. Now I’m gonna play, see what that does.

EDIT: Ikk. I tried it. It isn’t fun, but it works. Use the same repl (which I’m now using for two different questions - much more of this and I may need to split them). You’ll see a class Island (as in “no man is an”), which extends Person. In that, I do exactly what you want – ish. Because I’ve extended the Person class, I want to bind the methods of Person into the instance, so I use super.constructor.prototype.getAllMethods() to get those.

Then this[method] = this[method].bind(this) in the forEach loop. Here’s the problem – you’re creating methods on the instance with that, not on the class itself. You won’t access the super methods any longer, as the prototype tree has just been lopped at the current object.

Here’s the relevant code bit:

class Island extends Person{
  constructor(props){
    super(props);
    
    let myClassMethods = super.constructor.prototype.getAllMethods();
    myClassMethods.forEach(method => {
      this[method] = this[method].bind(this);
    })
  }
}
1 Like

The easiest solution is that you write something that compiles the class property version to the bind version. Which is what the Babel transform does (ie why the syntax just works in Create React App etc). The only way I can see this working is if you have a second object that the first instantiates (which is going to be terrible for performance), or I guess use a Proxy (which is going to be effectively the same, and again not really very performant)

1 Like
class Example {
    constructor(){}
    method1(){}
    method2(){}
}

var propertyNames = Object.getOwnPropertyNames(Example.prototype);
propertyNames.shift();

console.log(propertyNames);
// (2) ["method1", "method2"]

From within constructor:


class Example {
    
    constructor(){
        var proto = Object.getPrototypeOf(this);
        var methods = Object.getOwnPropertyNames(proto);
        methods.shift();
        console.log(methods);
    }

    method1(){}
    method2(){}

}

var x = new Example();
// (2) ["method1", "method2"]
1 Like

I would caution against blindly removing the first element of the array. It is, in all likelihood, the constructor, but do you really want to take that chance?

I’ve gone with this solution, which explicitly removes the constructor from the array.

const methods = Object.getOwnPropertyNames(
  this.constructor.prototype
).filter((m) => m !== 'constructor');
1 Like