Ottieni funzioni (metodi) di una class

Devo recuperare in modo dinamico le proprietà e le funzioni di una class ES6. È ansible?

Usando un ciclo for … in loop, posso solo scorrere le proprietà di un’istanza di class:

class Foo { constructor() { this.bar = "hi"; } someFunc() { console.log(this.bar); } } var foo = new Foo(); for (var idx in foo) { console.log(idx); } 

Produzione:

 bar 

Questa funzione otterrà tutte le funzioni. Ereditato o no, enumerabile o no. Tutte le funzioni sono incluse

 function getAllFuncs(obj) { var props = []; do { props = props.concat(Object.getOwnPropertyNames(obj)); } while (obj = Object.getPrototypeOf(obj)); return props.sort().filter(function(e, i, arr) { if (e!=arr[i+1] && typeof obj[e] == 'function') return true; }); } 

Fare test

getAllFuncs([1,3]);

uscita della console:

 ["constructor", "toString", "toLocaleString", "join", "pop", "push", "concat", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight", "entries", "keys", "constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", "__lookupSetter__"] 

Nota

Non restituisce funzioni definite tramite simboli;

I membri di una class non sono enumerabili . Per ottenerli, devi usare Object.getOwnPropertyNames :

 var propertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf(foo)); // or var propertyNames = Object.getOwnPropertyNames(Foo.prototype); 

Naturalmente questo non otterrà metodi ereditati. Non esiste un metodo che possa darti tutti loro. Dovresti attraversare la catena del prototipo e ottenere le proprietà per ogni prototipo individualmente.

ES6 aggiunge Reflection che rende il codice un po ‘più pulito.

 function getAllMethodNames(obj) { let methods = new Set(); while (obj = Reflect.getPrototypeOf(obj)) { let keys = Reflect.ownKeys(obj) keys.forEach((k) => methods.add(k)); } return methods; } /// a simple class hierarchy to test getAllMethodNames // kind of like an abstract base class class Shape { constructor() {} area() { throw new Error("can't define area for generic shape, use a subclass") } } // Square: a shape with a sideLength property, an area function and getSideLength function class Square extends Shape { constructor(sideLength) { super(); this.sideLength = sideLength; } area() { return this.sideLength * this.sideLength }; getSideLength() { return this.sideLength }; } // ColoredSquare: a square with a color class ColoredSquare extends Square { constructor(sideLength, color) { super(sideLength); this.color = color; } getColor() { return this.color } } let temp = new ColoredSquare(2, "red"); let methods = getAllMethodNames(temp); console.log([...methods]); 

Ci sono stati alcuni problemi nella risposta di @MuhammadUmer (simboli, indice i+1 , elenco dei metodi Object , ecc …) quindi, prendendo ispirazione da ciò, mi sono inventato questo

(avviso Typescript compilato per ES6)

 const getAllMethods = (obj) => { let props = [] do { const l = Object.getOwnPropertyNames(obj) .concat(Object.getOwnPropertySymbols(obj).map(s => s.toString())) .sort() .filter((p, i, arr) => typeof obj[p] === 'function' && //only the methods p !== 'constructor' && //not the constructor (i == 0 || p !== arr[i - 1]) && //not overriding in this prototype props.indexOf(p) === -1 //not overridden in a child ) props = props.concat(l) } while ( (obj = Object.getPrototypeOf(obj)) && //walk-up the prototype chain Object.getPrototypeOf(obj) //not the the Object prototype methods (hasOwnProperty, etc...) ) return props } 

Questa funzione elencherà tutti i metodi di un’istanza della class compresi quelli ereditati, ma il costruttore e quelli del prototipo Object.

Test

La funzione ritorna

 [ 'asyncMethod', 'echo', 'generatorMethod', 'ping', 'pong', 'anotherEcho' ] 

elencando i metodi di un’istanza di TestClass (typescript)

 class Echo { echo(data: string): string { return data } anotherEcho(data: string): string { return `Echo ${data}` } } class TestClass extends Echo { ping(data: string): string { if (data === 'ping') { return 'pong' } throw new Error('"ping" was expected !') } pong(data: string): string { if (data === 'pong') { return 'ping' } throw new Error('"pong" was expected !') } //overridden echo echo(data: string): string { return 'blah' } async asyncMethod(): Promise { return new Promise((resolve: (value?: string) => void, reject: (reason?: any) => void) => { resolve('blah') }) } * generatorMethod(): IterableIterator { yield 'blah' } } 

Per rendere enumerabili i membri della class puoi utilizzare Symbol.iterator

Ho dovuto ottenere tutti i metodi consentiti per l’object (compresi quelli ereditati). Così ho creato la class “Enumerable” e tutte le mie classi base ereditate da lui.

 class Enumerable { constructor() { // Add this for enumerate ES6 class-methods var obj = this; var getProps = function* (object) { if (object !== Object.prototype) { for (let name of Object.getOwnPropertyNames(object)) { let method = object[name]; // Supposedly you'd like to skip constructor and private methods (start with _ ) if (method instanceof Function && name !== 'constructor' && name[0] !== '_') yield name; } yield* getProps(Object.getPrototypeOf(object)); } } this[Symbol.iterator] = function*() { yield* getProps(obj); } // -------------- } }