Are there any 'harmonious' ways to get the class name from ES6 class instance? Other than
someClassInstance.constructor.name
Currently I'm counting on Traceur implementation. And it seems that Babel has a polyfill for Function.name while Traceur doesn't.
To sum it all up: there was no other way in ES6/ES2015/Harmony, and nothing is expected ATM in ES.Next.
It may provide useful patterns for unminified server-side applications but is unwanted in applications meant for browser/desktop/mobile.
Babel uses core-js to polyfill Function.name, it should be loaded manually for Traceur and TypeScript applications as appropriate.
As @Domenic says, use someClassInstance.constructor.name. @Esteban mentions in the comments that
someClassInstance.constructoris a Function. All Functions have anameproperty...
Thus, to access the class name statically, do the following (this works with my Babel version BTW. According to the comments on @Domenic your mileage may vary).
class SomeClass {
constructor() {}
}
var someClassInstance = new SomeClass();
someClassInstance.constructor.name; // === 'SomeClass'
SomeClass.name // === 'SomeClass'
Update
Babel was fine, but uglify/minification did end up causing me problems. I am making a game, and am creating a hash of pooled Sprite resources (where the key is the function name). After minification, every function/class was named t. This kills the hash. I am using Gulp in this project, and after reading the gulp-uglify docs I discovered there is a parameter to prevent this local variable/function name mangling from happening. So, in my gulpfile I changed
.pipe($.uglify()) to .pipe($.uglify({ mangle: false }))
There is a trade-off of performance vs readability here. Not mangling the names will result in a (slightly) larger build file (more network resources) and potentially slower code execution (citation needed - may be BS). On the other hand, if I kept it the same I would have to manually define getClassName on every ES6 class - at a static and instance level. No thanks!
Update
After the discussion in the comments, it seems like avoiding the .name convention in favor of defining those functions is a good paradigm. It only takes a few lines of code, and will allow full minification and generality of your code (if used in a library). So I guess I change my mind and will manually define getClassName on my classes. Thanks @estus!. Getter/Setters are usually a good idea compared to direct variable access anyways, especially in a client based application.
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)
Previous answers explained that someClassInstance.constructor.name works just fine, but if you need to programmatically convert class name into a string and don't want to create an instance just for that, remember that:
typeof YourClass === "function"
And, since every function has a name property, another nice way to get a string with your class name is to just do:
YourClass.name
What follows is a good example of why this is useful.
As the MDN documentation teaches us, this is how you load a web component:
customElements.define("your-component", YourComponent);
Where YourComponent is a class extending from HTMLElement. Since it is considered good practice to name your component's class after the component tag itself, it would be nice to write a helper function that all your components could use to register themselves. So here's is that function:
function registerComponent(componentClass) {
const componentName = upperCamelCaseToSnakeCase(componentClass.name);
customElements.define(componentName, componentClass);
}
So all you need to do is:
registerComponent(YourComponent);
Which is nice because it's less error-prone than writing the component tag yourself. To wrap it up, this is the upperCamelCaseToSnakeCase() function:
// 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());
}