ES6クラスのプロパティと機能を動的に取得する必要があります。これも可能ですか?
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 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;
});
}
テストを行う
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);
もちろん、これは継承されたメソッドを取得しません。それらすべてを提供できる方法はありません。プロトタイプチェーンを走査して、各プロトタイプのプロパティを個別に取得する必要があります。
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]);
@MuhammadUmerの回答にはいくつかの問題がありました(シンボル、インデックスi+1
、Object
メソッドのリストなど)、そこからインスピレーションを得て、私はこれを思いつきました
(ES6にコンパイルされた警告TypeScript)
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
}
この関数は、継承されたものを含むクラスのインスタンスのallメソッド、butコンストラクター、およびObjectプロトタイプのメソッドをリストします。
関数は戻ります
[ 'asyncMethod',
'echo',
'generatorMethod',
'ping',
'pong',
'anotherEcho' ]
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<string> {
return new Promise<string>((resolve: (value?: string) => void, reject: (reason?: any) => void) => {
resolve('blah')
})
}
* generatorMethod(): IterableIterator<string> {
yield 'blah'
}
}
クラスのメンバーを列挙可能にするには、Symbol.iteratorを使用できます
オブジェクトのすべての許可されたメソッド(継承を含む)を取得する必要がありました。そこで、「Enumerable」クラスを作成し、すべての基本クラスを彼から継承しました。
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);
}
// --------------
}
}