web-dev-qa-db-fra.com

Obtenir le nom de classe de l'instance de classe ES6

Existe-t-il des méthodes "harmonieuses" pour obtenir le nom de classe à partir d'une instance de classe ES6? Autre que

_someClassInstance.constructor.name
_

Actuellement, je compte sur la mise en œuvre de Traceur. Et il semble que Babel ait un polyfill pour _Function.name_ alors que Traceur ne l’a pas.

Pour résumer le tout: il n'y avait pas d'autre moyen d'ES6/ES2015/Harmony, et rien n'est attendu de type ATM dans ES.Next.

Il peut fournir des modèles utiles pour les applications côté serveur non minées, mais est indésirable dans les applications destinées à un navigateur/un ordinateur de bureau/un téléphone mobile .

Babel tilise _core-js_ pour polyfill Function.name , il doit être chargé manuellement pour les applications Traceur et TypeScript, selon le cas. .

134
Estus Flask

someClassInstance.constructor.name est exactement la bonne façon de faire cela. Transpilers peut ne pas supporter cela, mais c'est la manière standard selon les spécifications. (La propriété name des fonctions déclarées via les productions ClassDeclaration est définie à 14.5.15 , étape 6.)

174
Domenic

Comme @Domenic dit, utilisez someClassInstance.constructor.name. @Esteban mentionne dans les commentaires que

someClassInstance.constructor est une fonction. Toutes les fonctions ont une propriété name ...

Ainsi, pour accéder au nom de la classe de manière statique, procédez comme suit (cela fonctionne avec ma version de Babel BTW. Selon les commentaires sur @ Domenic, votre kilométrage peut varier).

class SomeClass {
  constructor() {}
}

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

Mettre à jour

Babel allait bien, mais uglify/minification a fini par me causer des problèmes. Je crée un jeu et je crée un hachage de ressources Sprite en pool (où la clé est le nom de la fonction). Après minification, chaque fonction/classe s’appelait t. Cela tue le hash. J'utilise Gulp dans ce projet, et après avoir lu la documentation gulp-uglify , j'ai découvert qu'il existait un paramètre permettant d'éviter que cette variable locale/ce nom de fonction ne se reproduise. Donc, dans mon gulpfile j'ai changé

.pipe($.uglify()) à .pipe($.uglify({ mangle: false }))

Ici, il y a un compromis entre performance et lisibilité. Ne pas modifier les noms entraînera un fichier de construction (légèrement) plus volumineux (plus de ressources réseau) et potentiellement une exécution plus lente du code (citation nécessaire - peut-être BS). D'un autre côté, si je le conservais, je devrais définir manuellement getClassName sur chaque classe ES6 - aux niveaux statique et instance. Non merci!

Mettre à jour

Après la discussion dans les commentaires, il semble que le fait d'éviter la convention .name en faveur de la définition de ces fonctions constitue un bon paradigme. Cela ne prend que quelques lignes de code, et permettra une minification complète et la généralité de votre code (si utilisé dans une bibliothèque). Je suppose donc que je change d’avis et que je définirai manuellement getClassName dans mes classes. Merci @ estus! . Les accesseurs/régleurs sont généralement une bonne idée par rapport à un accès direct variable, en particulier dans une application basée sur le client.

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)
45
James L.

Obtenir le nom de la classe directement à partir de la classe

Les réponses précédentes expliquaient que someClassInstance.constructor.name fonctionnait parfaitement, mais si vous devez convertir le nom de la classe par programme en chaîne et que vous ne voulez pas créer une instance pour cela, rappelez-vous que:

typeof YourClass === "function"

Et, comme chaque fonction a une propriété name, une autre façon pratique d’obtenir une chaîne avec votre nom de classe est de faire:

YourClass.name

Ce qui suit est un bon exemple de la raison pour laquelle cela est utile.

Chargement de composants Web

Comme le documentation MDN nous apprend, voici comment charger un composant Web:

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

YourComponent est une classe allant de HTMLElement. Etant donné qu'il est considéré comme une bonne pratique de nommer la classe de votre composant après la balise de composant elle-même, il serait agréable d'écrire une fonction d'assistance que tous vos composants pourraient utiliser pour s'enregistrer eux-mêmes. Voici donc cette fonction:

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

Donc tout ce que vous devez faire c'est:

registerComponent(YourComponent);

Ce qui est agréable car il est moins sujet aux erreurs que d’écrire la balise de composant vous-même. Pour terminer, voici la fonction 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