获取 ES6类实例的类名

有没有什么“和谐”的方法可以从 ES6类实例中获得类名

someClassInstance.constructor.name

目前我指望 Traceur 的实现,而且看起来 Babel 有 Function.name的填充物,而 Traceur 没有。

总而言之: ES6/ES2015/Harmony 中没有其他方法,也不期望在 ESS 中使用 ATM。

它可以为非小型化的服务器端应用程序提供有用的模式,但在浏览器/桌面/移动应用程序中是不需要的。

Babel 使用 core-js填充 Function.name,它应该手动加载的 Traceur 和 TypeScript 应用程序作为适当的。

124844 次浏览

someClassInstance.constructor.name正是这样做的正确方法。透视器可能不支持这一点,但它是每个规范的标准方式。(通过 ClassDeclaration 产生式声明的函数的 name属性在 14.515步骤6中设置。)

正如@Domenic 所说,使用 someClassInstance.constructor.name。@Esteban 在评论中提到

所有函数都有一个 name属性..。

因此,要静态访问类名,请执行以下操作(这适用于我的 Babel 版本 BTW。根据@Domenic 上的评论,你的成绩可能会有所不同)。

class SomeClass {
constructor() {}
}


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

更新

巴别塔还好,但丑化/缩小确实给我带来了麻烦。我正在制作一个游戏,并且正在创建一个混合 Sprite 资源的散列(其中的关键字是函数名)。缩小后,每个函数/类都被命名为 t。这会毁了大麻。我在这个项目中使用的是 Gulp,在阅读了 吞下丑陋的文件之后,我发现有一个参数可以防止本地变量/函数名被破坏。所以,在我的吞咽文件中,我改变了

.pipe($.uglify())呼叫 .pipe($.uglify({ mangle: false }))

这里需要在性能和可读性之间进行权衡。不损坏名称将导致(稍微)更大的构建文件(更多的网络资源)和潜在的更慢的代码执行(需要引用-可能是 BS)。另一方面,如果保持不变,我将不得不在每个 ES6类上手动定义 getClassName——在静态和实例级别。不用了,谢谢!

更新

在评论中讨论之后,似乎可以避免使用 .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)

直接从类获取类名

以前的答案解释说,someClassInstance.constructor.name工作得很好,但是如果您需要通过编程将类名转换为字符串,并且不想仅仅为此创建实例,请记住:

typeof YourClass === "function"

而且,由于每个函数都有一个 name属性,另一个获得具有类名的字符串的好方法是:

YourClass.name

下面是一个很好的例子来说明为什么这是有用的。

正在加载 Web 组件

正如 MDN 文档告诉我们的,这就是你如何加载一个 web 组件:

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

其中 YourComponent是从 HTMLElement扩展的类。因为用组件标记本身来命名组件的类被认为是一种很好的做法,所以最好编写一个 helper 函数,所有组件都可以用它来注册自己。这就是那个函数:

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

用于巴别塔翻译(缩小前)

如果在 @babel/preset-env中使用 Babel,则可以保留类定义,而不必将它们转换为函数(这将删除 constructor属性)

您可以在 babel.config / babelrc中删除一些旧的浏览器与这个配置的兼容性:

{
"presets": [
["@babel/preset-env", {"targets": {"browsers": ["> 2%"]}}]
]
}

更多关于 targets: https://babeljs.io/docs/en/babel-preset-env#targets的信息

用于巴别塔缩小(翻译后)

看起来现在没有简单的解决办法... 我们需要看看错误的排除。

如果您控制了类的实现

我在这里添加这个,因为它是顶部的谷歌时,我试图找出如何做到这一点。

这似乎是为我工作的节点。

./SuperClass.js

'use strict';


/**
* A super class
*
* To show that it works with inheritance too
*
* In my usage, I'm also extending the Error class
*/
module.exports = class SuperClass extends Error {
constructor(message, options = {}) {
super(message);
this.name = this.constructor.name;
// ...other shared construction functionality
}
};

./SubClass.js

'use strict';


const SuperClass = require('./SuperClass');
/**
* a sub class
*/
module.exports = class SubClass extends SuperClass {
constructor(message, options = {}) {
super(message, options);
// ... specific sub class construction functionality
}
};
SubClass.name; // -> 'SubClass'
let instance = new SubClass('message');
instance.name; // -> 'SubClass'

显然,这只适用于您拥有完全实现控制权的类。

我可能会把它改为 _name或其他什么,但这是为了使它与我正在使用的另一个库保持一致。