获取类的函数(方法)
我必须dynamic获取ES6类的属性和function。 这甚至有可能吗?
使用for … in循环,我只能循环访问类实例的属性:
class Foo { constructor() { this.bar = "hi"; } someFunc() { console.log(this.bar); } } var foo = new Foo(); for (var idx in foo) { console.log(idx); }
输出:
bar
该function将获得所有function。 inheritance与否,可枚举与否。 所有function都包括在内。
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; }); }
做testing
getAllFuncs([1,3]);
控制台输出:
["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__"]
一个类的成员是不可枚举的 。 为了得到它们,你必须使用Object.getOwnPropertyNames
:
var propertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf(foo)); // or var propertyNames = Object.getOwnPropertyNames(Foo.prototype);
当然这不会得到inheritance的方法。 没有办法可以给你所有的人。 您将不得不遍历原型链并分别获取每个原型的属性。
对于我来说,在@MuhammadUmer答案中有几个问题(符号,索引i+1
, Object
方法的列表等等),所以从中得到灵感,我想出了这个
(警告Typescript编译为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 }
这个函数将列出类的一个实例的所有方法,包括那些inheritance的, 但是构造器和Object原型的。
testing
函数返回
[ 'asyncMethod', 'echo', 'generatorMethod', 'ping', 'pong', 'anotherEcho' ]
列出TestClass
(打字稿)实例的方法
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<string> { return new Promise<string>((resolve: (value?: string) => void, reject: (reason?: any) => void) => { resolve('blah') }) } * generatorMethod(): IterableIterator<string> { yield 'blah' } }
ES6增加了Reflection,这使得代码做得更干净一些。
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]);
要使类的成员可枚举,可以使用Symbol.iterator
我必须得到所有允许的对象的方法(包括inheritance)。 所以我创build了类“Enumerable”和所有我的基类从他inheritance。
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); } // -------------- } }