1つのモジュールから次のES6クラスをエクスポートしています。
export class Thingy {
hello() {
console.log("A");
}
world() {
console.log("B");
}
}
そして、別のモジュールからインポートする:
import {Thingy} from "thingy";
if (isClass(Thingy)) {
// Do something...
}
変数がクラスかどうかを確認するにはどうすればよいですか?クラスインスタンスではなく、クラス宣言?
言い換えると、上記の例でisClass
関数をどのように実装しますか?
ここで前もって明確にします。任意の関数はコンストラクターになります。 「クラス」と「関数」を区別している場合は、API設計の選択が不十分です。たとえば、何かがclass
でなければならない場合、そのコードは代わりに関数に変換されるため、BabelやTypeScriptを使用している人はclass
として検出されません。つまり、コードベースmustを使用するすべての人がES6環境で一般的に実行するように義務付けられているため、コードは古い環境では使用できなくなります。
ここでのオプションは、実装定義の動作に制限されています。 ES6では、コードが解析され、構文が処理されると、クラス固有の動作はほとんど残りません。必要なのは、コンストラクター関数だけです。あなたの最善の選択はすることです
_if (typeof Thingy === 'function'){
// It's a function, so it definitely can't be an instance.
} else {
// It could be anything other than a constructor
}
_
また、誰かが非コンストラクター関数を実行する必要がある場合は、そのための別のAPIを公開します。
明らかにそれはあなたが探している答えではありませんが、それを明確にすることが重要です。
ここでの他の答えが言及しているように、クラス宣言を返すには関数の.toString()
が必要なため、オプションがあります。
_class Foo {}
Foo.toString() === "class Foo {}" // true
_
ただし、重要なのは、可能な場合のみを適用することです。実装が100%仕様に準拠している
_class Foo{}
Foo.toString() === "throw SyntaxError();"
_
いいえブラウザ現在それを行いますが、たとえばJSプログラミングに焦点を当てた組み込みシステムがいくつかあり、プログラム自体のメモリを保持するために、解析されたソースコードを破棄します。 .toString()
から返すソースコードがなく、許可されています。
同様に、.toString()
を使用することにより、将来の保証と一般的なAPI設計の両方についての仮定を立てています。あなたが言う
_const isClass = fn => /^\s*class/.test(fn.toString());
_
これは文字列表現に依存しているため、簡単に破損する可能性があります。
デコレータを例に取ります:
_@decorator class Foo {}
Foo.toString() == ???
_
この.toString()
にはデコレータが含まれていますか?デコレータ自体がクラスではなくfunction
を返すとどうなりますか?
値が関数だけでなく、実際にはクラスのコンストラクター関数であることを確認する場合は、関数を文字列に変換し、その表現を検査できます。 仕様では、クラスコンストラクターの文字列表現が規定されています 。
function isClass(v) {
return typeof v === 'function' && /^\s*class\s+/.test(v.toString());
}
別の解決策は、値を通常の関数として呼び出すことです。クラスコンストラクターは通常の関数としては呼び出しできませんが、エラーメッセージはおそらくブラウザーによって異なります。
function isClass(v) {
if (typeof v !== 'function') {
return false;
}
try {
v();
return false;
} catch(error) {
if (/^Class constructor/.test(error.message)) {
return true;
}
return false;
}
}
欠点は、関数を呼び出すと、あらゆる種類の未知の副作用が発生する可能性があることです...
たぶんこれは助けることができます
let is_class = (obj) => {
try {
new obj();
return true;
} catch(e) {
return false;
};
};