182

是否有任何“和谐”的方法可以从 ES6 类实例中获取类名?以外

someClassInstance.constructor.name

目前我指望 Traceur 实施。而且似乎 Babel 有一个 polyfill,Function.name而 Traceur 没有。

综上所述:在 ES6/ES2015/Harmony 中没有其他方法,在 ES.Next 中没有任何预期的 ATM。

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

Babel用于core-jspolyfill Function.name,应根据需要为 Traceur 和 TypeScript 应用程序手动加载。

4

4 回答 4

235

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

于 2015-05-31T17:43:59.817 回答
62

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

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

因此,要静态访问类名,请执行以下操作(这适用于我的 Babel 版本顺便说一句。根据@Domenic 上的评论,您的里程可能会有所不同)。

class SomeClass {
  constructor() {}
}

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

更新

Babel 很好,但 uglify/minification 确实给我带来了问题。我正在制作游戏,并正在创建池化 Sprite 资源的哈希(其中键是函数名称)。缩小后,每个函数/类都被命名为t. 这会杀死哈希。我Gulp在这个项目中使用,在阅读了gulp-uglify 文档后,我发现有一个参数可以防止这个局部变量/函数名发生错误。所以,在我的 gulpfile 中我改变了

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

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

更新

在评论中的讨论之后,似乎避免.name约定以定义这些函数是一个很好的范例。它只需要几行代码,并且允许您的代码完全缩小和通用性(如果在库中使用)。所以我想我改变了主意,将手动定义getClassName我的课程。谢谢@estus!. 无论如何,与直接变量访问相比,Getter/Setter 通常是一个好主意,尤其是在基于客户端的应用程序中。

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)
于 2016-09-16T01:01:22.290 回答
12

直接从类中获取类名

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

typeof YourClass === "function"

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

YourClass.name

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

加载 Web 组件

正如MDN 文档告诉我们的那样,这是加载 Web 组件的方式:

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());
}
于 2018-09-15T22:35:34.890 回答
2

用于 babel 转译(缩小之前)

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

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

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

更多信息targetshttps ://babeljs.io/docs/en/babel-preset-env#targets

用于 babel 缩小(转译后)

看起来现在没有简单的解决方案......我们需要看看修改排除。

于 2020-05-26T16:06:21.507 回答