概要
Javascriptでクラスを判定してメンバを列挙する必要が出てきたのでやり方を探してみた。
Node.js・Chromeで確認
JavaScriptのクラス関係の命名がよくわからなかったのでJava基準で
クラスの判別
クラス・インスタンスを普通にtypeofに通すとクラスはfunction
、インスタンスはobject
と返ります。JavaScriptのクラスが単なる糖衣構文に過ぎないことがよくわかります。
class TestClass {
static classMethodTest(){}
static classFieldTest;
static arguments;
instanceMethodTest(){}
instanceFieldTest;
}
let TestObject = {
constructor: ''
}
let TestFunction = function() {
}
let TestInstance = new TestClass();
console.log(typeof TestClass); // "function"
console.log(typeof TestInstance); // "object"
クラスであることを判定するにはtoString()でコードを取得して先頭がclassであるかどうかを確認するのが確実なんじゃないかと思います。
一応クラスにはfunctionオブジェクトにあるはずのargument
プロパティがないのですが、自分でargumentクラスフィールドを追加したら判別のしようがなくなるので・・・
console.log(TestClass.toString().startsWith('class')); //true
インスタンスの場合はconstructor
プロパティでクラスを取得できるはずなのでそこからtoString()
でクラスかどうかを判別します。
console.log(TestInstance.constructor.toString().startsWith('class')); //true
基底クラスの取得
Object.getPrototypeOf(TestClass);
とすると基底クラスを取得できます。
ルートクラスにあたるObjectクラス?に行き当たるとtoStringの結果がfunction () { [native code] }
になるので基底クラスを辿っていくのは簡単です。
thisobj = TestClass;
while (true) {
classname = thisobj.name;
console.log(classname);
thisobj = Object.getPrototypeOf(thisobj);
if (!thisobj.toString().startsWith('class')) break;
}
メンバの列挙
クラスに定義したメンバはなぜかObject.keys()
では取得できません、代わりにObject.getOwnPropertyNames()
を使います。
JavaScriptには列挙可能なプロパティと列挙不可能なプロパティってのがあるらしくObject.Keys()で取得できるのは前者だけだかららしい。
//(1) ['constructor']
console.log(Object.getOwnPropertyNames(TestObject));
//(5) ['length', 'name', 'arguments', 'caller', 'prototype']
console.log(Object.getOwnPropertyNames(TestFunction));
//(6) ['length', 'name', 'prototype', 'classMethodTest', 'classFieldTest', 'arguments']
console.log(Object.getOwnPropertyNames(TestClass));
//(2) ['constructor', 'instanceMethodTest']
console.log(Object.getOwnPropertyNames(TestClass.prototype));
//(1) ['instanceFieldTest']
console.log(Object.getOwnPropertyNames(TestInstance));
クラスメソッド・フィールドの列挙はクラスから、インスタンスメソッドの列挙はクラスのprototypeプロパティから、インスタンスフィールドの列挙はインスタンスからしかできないらしい。