Получить имя класса экземпляра класса ES6

Есть ли "гармоничные" способы получить имя класса из экземпляра класса ES6? Кроме

someClassInstance.constructor.name

В настоящее время я рассчитываю на реализацию Traceur. И похоже, что у Babel есть polyfill для Function.name, в то время как Traceur этого не делает.

Подводя итог: в ES6/ES2015/Harmony не было другого способа, и ничего не ожидается. ATM в ES.Next.

Он может предоставлять полезные шаблоны для неиниминированных серверных приложений, но нежелателен в приложениях, предназначенных для браузера/рабочего стола/мобильного телефона.

Babel использует core-js для polyfill Function.name, он должен быть загружен вручную для приложений Traceur и TypeScript, если это необходимо.

Ответ 1

someClassInstance.constructor.name - это точно правильный способ сделать это. Transpilers может не поддерживать это, но это стандартный способ для спецификации. (Свойство name функций, объявленных через ClassDeclaration productions, установлено в пункте 14.5.15, шаг 6.)

Ответ 2

Как говорит @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'

Обновление

Вавилон был в порядке, но углифицировать/минимизировать закончилось тем, что вызвало у меня проблемы. Я делаю игру и создаю хэш объединенных ресурсов Sprite (где ключ - это имя функции). После минимизации каждая функция/класс была названа t. Это убивает хэш. Я использую Gulp в этом проекте, и после прочтения gulp -uglify docs я обнаружил, что существует параметр для предотвращения этой локальной переменной /function name mangling из происходит. Итак, в моем gulpfile я изменил

.pipe($.uglify()) до .pipe($.uglify({ mangle: false }))

Здесь есть компромисс производительности и читаемости. Неправильное использование имен приведет к (чуть большему) файлу сборки (больше сетевых ресурсов) и потенциально медленному выполнению кода (ссылка - может быть BS). С другой стороны, если бы я сохранил то же самое, мне пришлось бы вручную определять getClassName для каждого класса ES6 - на статическом уровне и уровне экземпляра. Нет, спасибо!

Обновление

После обсуждения в комментариях кажется, что избегать соглашения .name в пользу определения этих функций является хорошей парадигмой. Это занимает всего несколько строк кода и позволит полностью минимизировать и обобщать ваш код (если используется в библиотеке). Поэтому, я думаю, я передумаю и вручную определю getClassName для своих классов. Спасибо @estus!. Getter/Setters - это, как правило, хорошая идея по сравнению с прямым доступом к переменной в любом случае, особенно в клиентском приложении.

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)

Ответ 3

Получение имени класса непосредственно из класса

Предыдущие ответы объяснили, что someClassInstance.constructor.name работает нормально, но если вам нужно программно преобразовать имя класса в строку и не хотите создавать экземпляр именно для этого, помните, что:

typeof YourClass === "function"

И поскольку каждая функция имеет свойство name, другой хороший способ получить строку с вашим именем класса - это просто сделать:

YourClass.name

Ниже следует хороший пример того, почему это полезно.

Загрузка веб-компонентов

Как учит нам документация MDN, так вы загружаете веб-компонент:

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

Где YourComponent - класс, распространяющийся от HTMLElement. Поскольку считается хорошей практикой назвать ваш класс компонента после самого тега компонента, было бы неплохо написать вспомогательную функцию, которую все ваши компоненты могли бы использовать для регистрации. Итак, вот эта функция:

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());
}