web-dev-qa-db-ja.com

ES6クラスインスタンスのクラス名を取得

ES6クラスインスタンスからクラス名を取得するための「調和のとれた」方法はありますか?以外

someClassInstance.constructor.name

現在私はTraceurの実装を頼りにしています。そして、BaburはFunction.nameのためのpolyfillを持っていますが、Traceurは持っていません。

まとめると、ES6/ES2015/Harmonyには他に方法はありませんでした。ES.NextではATMは想定されていません。

これは、縮小されていないサーバーサイドアプリケーションに有用なパターンを提供するかもしれませんが、ブラウザ/デスクトップ/モバイル向けのアプリケーションでは望ましくありません。

Babel core-js をpolyfillに使用する Function.name 、TraceurとTypeScriptアプリケーションには適宜手動でロードしてください。

130
Estus Flask

someClassInstance.constructor.nameはまさにこれを行う正しい方法です。 Transpilerはこれをサポートしないかもしれませんが、それは仕様に従って標準的な方法です。 (ClassDeclarationプロダクションを介して宣言された関数のnameプロパティは 14.5.15 、ステップ6に設定されています。)

169
Domenic

@Domenicが言うように、someClassInstance.constructor.nameを使用してください。 @Estebanは、コメントで言及していること

someClassInstance.constructorは関数です。すべての関数はnameプロパティを持っています...

したがって、静的にクラス名にアクセスするには、次のようにします(これは私のBabelバージョンBTWで動作します。@Domenicのコメントによると、あなたの走行距離は変わるかもしれません)。

class SomeClass {
  constructor() {}
}

var someClassInstance = new SomeClass();
someClassInstance.constructor.name;      // === 'SomeClass'
SomeClass.name                           // === 'SomeClass'

更新

Babelは大丈夫だったが、醜化/縮小は結局私に問題を引き起こした。私はゲームを作っていて、プールされたSpriteリソースのハッシュを作成しています(キーは関数名です)。縮小後、すべての関数/クラスはtと命名されました。これはハッシュを殺します。私はこのプロジェクトでGulpを使用しています、そして gulp-uglify docs を読んだ後、このローカル変数/関数名のマングリングを防ぐためのパラメータがあることを発見しました。だから、私のgulpファイルで私は変更しました

.pipe($.uglify())から.pipe($.uglify({ mangle: false }))

ここではパフォーマンスと読みやすさの間にトレードオフがあります。名前を乱さないと(少し)大きなビルドファイル(より多くのネットワークリソース)と潜在的により遅いコード実行(引用が必要です - BSかもしれません)をもたらすでしょう。一方、同じままにしておくと、すべてのES6クラスで静的およびインスタンスレベルでgetClassNameを手動で定義する必要があります。結構です!

更新

コメントでの議論の後、それらの関数を定義するために.name規約を避けることは良いパラダイムのようです。数行のコードしか必要とせず、あなたのコードの完全な縮小と一般化を可能にします(ライブラリで使用されている場合)。ですから、考えを変えて、クラスにgetClassNameを手動で定義するつもりです。ありがとう @ estus! 。とくにクライアントベースのアプリケーションでは、直接変数アクセスと比較して、ゲッター/セッターは通常は良い考えです。

class SomeClass {
  constructor() {}
  static getClassName(){ return 'SomeClass'; }
  getClassName(){ return SomeClass.getClassName(); }
}
var someClassInstance = new SomeClass();
someClassInstance.constructor.getClassName();      // === 'SomeClass' (static fn)
someClassInstance.getClassName();                  // === 'SomeClass' (instance fn)
SomeClass.getClassName()                           // === 'SomeClass' (static fn)
44
James L.

クラスから直接クラス名を取得

前の回答ではsomeClassInstance.constructor.nameは問題なく動作すると説明しましたが、プログラムでクラス名を文字列に変換する必要があり、そのためだけにインスタンスを作成したくない場合は、次の点に注意してください。

typeof YourClass === "function"

そして、すべての関数がnameプロパティを持っているので、あなたのクラス名で文字列を取得するもう一つの良い方法はただすることです:

YourClass.name

以下は、これが便利な理由の良い例です。

Webコンポーネントを読み込む

MDNドキュメント が教えてくれるように、これがWebコンポーネントのロード方法です。

customElements.define("your-component", YourComponent);

YourComponentHTMLElementから拡張するクラスです。コンポーネントのタグ自体の名前に基づいてコンポーネントのクラスに名前を付けるのは良い習慣と考えられているので、すべてのコンポーネントが自分自身を登録するために使用できるヘルパー関数を書くのはいいでしょう。これがその機能です。

function registerComponent(componentClass) {
    const componentName = upperCamelCaseToSnakeCase(componentClass.name);
    customElements.define(componentName, componentClass);
}

だからあなたがする必要があるのは次のとおりです。

registerComponent(YourComponent);

コンポーネントタグを自分で記述するよりもエラーが発生しにくいので、これはいい方法です。まとめると、これはupperCamelCaseToSnakeCase()関数です。

// converts `YourString` into `your-string`
function upperCamelCaseToSnakeCase(value) {
    return value
        // first char to lower case
        .replace(/^([A-Z])/, $1 => $1.toLowerCase())
        // following upper chars get preceded with a dash
        .replace(/([A-Z])/g, $1 => "-" + $1.toLowerCase());
}
5
Lucio Paiva