获取 ES6 class 实例的 class 名称

Get the class name of ES6 class instance

是否有任何 'harmonious' 方法从 ES6 class 实例中获取 class 名称?除了

someClassInstance.constructor.name

目前我指望 Traceur 实现。 Babel 似乎有 Function.name 的 polyfill,而 Traceur 没有。

总而言之:在ES6/ES2015/Harmony没有别的办法,在ES.Next.

也没有ATM。

它可能为未缩小的服务器端应用程序提供有用的模式,但在用于 browser/desktop/mobile 的应用程序中不需要。

Babel uses core-js to polyfill Function.name,应酌情为 Traceur 和 TypeScript 应用程序手动加载。

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

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

someClassInstance.constructor is a Function. All Functions have a name property...

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

class SomeClass {
  constructor() {}
}

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

更新

Babel 很好,但 uglify/minification 确实给我带来了麻烦。我正在制作游戏,并正在创建池化 Sprite 资源的哈希(其中键是函数名称)。缩小后,每个 function/class 被命名为 t。这会杀死哈希。我在这个项目中使用 Gulp,在阅读 gulp-uglify docs 之后,我发现有一个参数可以防止这个本地 variable/function 名称重整发生。所以,在我的 gulpfile 中我改变了

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

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

更新

经过评论中的讨论,似乎避免 .name 约定而支持定义这些函数是一个很好的范例。它只需要几行代码,并且允许完全缩小和通用代码(如果在库中使用)。所以我想我改变了主意,将在我的 classes 上手动定义 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)

直接从class

获取class名字

之前的答案解释说 someClassInstance.constructor.name 工作正常,但是如果您需要以编程方式将 class 名称转换为字符串并且不想为此创建一个实例,请记住:

typeof YourClass === "function"

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

YourClass.name

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

正在加载网络组件

正如 MDN documentation 教导我们的那样,这就是加载 Web 组件的方式:

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

其中 YourComponent 是从 HTMLElement 延伸而来的 class。由于在组件标签本身之后命名组件的 class 被认为是一种很好的做法,因此编写一个所有组件都可以用来注册自己的辅助函数会很好。所以这是函数:

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])/,  => .toLowerCase())
        // following upper chars get preceded with a dash
        .replace(/([A-Z])/g,  => "-" + .toLowerCase());
}

用于 babel 转译(缩小之前)

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

您可以在 babel.config / babelrc:

中删除一些与此配置的旧浏览器兼容性
{
  "presets": [
    ["@babel/preset-env", {"targets": {"browsers": ["> 2%"]}}]
  ]
}

More informations about targets : https://babeljs.io/docs/en/babel-preset-env#targets

用于 babel 缩小(转译后)

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