【问题标题】:ES6 Dynamic class namesES6 动态类名
【发布时间】:2016-02-09 21:37:40
【问题描述】:

我一直在尝试 ES6 类,想知道是否可以动态更改类名?例如

class [Some dynamic name] {}; 

【问题讨论】:

  • 你为什么想要一个类的动态名称?有什么意义?
  • 这说明了一切。 instance 应该是动态的,而不是您的类模板,但如果您确信这是正确的方法,您可以创建一个标准函数 using the Function constructor 并像在 ES5 中一样使用原型。或者使用像 Gulp/Grunt 这样运行的任务来生成预构建类
  • 如果使用 ES5 类,则使用 let tmp = { [name](){} }; 并访问该命名函数 o[name]。如果我们可以通过类做到这一点会很酷:let o = { class [name] {} }.
  • @CodingIntrigue 我来这里是为了寻找一些东西(阅读动态类创建),但是您的评论“使用像 Gulp/Grunt 这样运行的任务来生成类”让我朝着不同的方向前进,这解决了很多问题我没有想到的问题。谢谢......
  • 确实如此。实例应该是动态的,而不是您的类模板。我非常不同意。来自高度静态的 Java,我很欣赏 JS 每天都更加动态。我想动态设置一个类名,这样我的类就不会是匿名的。我想动态创建类,因为我正在开发一个库来创建和使用 mixins 来实现 ES6 类的多重继承。我使用经典继承的时间越长,我就越相信单继承不会削减它。 JS 很棒 因为它是动态的,尽管如此。

标签: javascript class ecmascript-6


【解决方案1】:
let C = class
{ // ...
}
Object.defineProperty (C, 'name', {value: 'TheName'});

// test: 
let itsName =  (new C()).constructor.name;
// itsName === 'TheName' -> true

【讨论】:

  • 您好,如果您提供代码说明将会很有帮助。
  • 我相信这是正确的答案。 注意Object.defineProperty(C, 'name', ...) 有效,C.name = ... 抛出 Script Error: "name" is read-only(至少在 Firefox 中)。
  • 这应该是正确答案,接受的答案类没有名字。
  • 是的,这是截至当前日期的正确答案。在类定义本身中没有办法这样做
  • Object.defineProperty() 是否应该允许修改只读属性,或者这只是一个不应该存在的实现怪癖?
【解决方案2】:

有一个非常简单的方法:

const nameIt = (name, cls) => ({[name] : class extends cls {}})[name];

Here的演示。

它使用对象字面量来定义一个具有所需名称的字段,该名称将包含一个新类。这会导致新类自动获得所需的名称。完成后,我们提取该新类并将其返回。

注意对象字面量周围的括号,以免花括号被误认为是代码块(...) => {...}

当然,将现有类放入命名字段不会更改类,因此只有在创建新类时才有效。如果您只需要在一个定义要命名的类的地方使用动态名称,则可以删除额外的继承,然后继续:

const myClass = {[name]: class {
    ...
}}[name];

【讨论】:

  • 我们也可以添加方法吗?并再次添加新的属性??
  • 如果我们有一个静态方法将类称为“this”,则此技术将不起作用。示例:static create = (args) => new this(args); 在这种情况下,名称将是“_class”
【解决方案3】:

对于您想要实现的任何目标,可能有更好的解决方案,但您可以将类表达式分配给对象:

let classes = {};
classes[someName] = class { ... };

这在 ES2015 中并没有真正改变:如果你想创建一个动态命名的绑定,你必须使用一个对象或其他映射来代替。

【讨论】:

  • 实际上,ES6 的变化在于类的.name 现在是someName
  • 或者等等,那只是在{[someName]: class {…}}
  • 如何在这样的类表达式中添加装饰器?
  • @FabianZeindl:没有理由这不应该工作,因为这个标准实践甚至在 ES6 之前就已经存在(当然 class 值除外)。
  • 我再次检查,我有一个自定义的 babel-transform,它意外禁用了它。
【解决方案4】:

为了更进一步地使用动态类名和动态继承,在使用 babel 时,你可以这样做:

    function withname(name, _parent) {
        return class MyDinamicallyNamedClass extends (_parent||Object) {
            static get name() { return name || _parent.name }
        }
    }

【讨论】:

  • 但是控制台仍然输出class MyDinamicallyNamedClass ...
  • 是的,但我认为他的意思是       (MyDinamicallyNamedClass instanceof _parent) 返回真 \n       (顺便说一句,这不是你动态拼写的方式,lOlz)
【解决方案5】:

使用eval 的方法很简单,即使不是很理想:

~function() {
    const name = "Lorem"

    eval(`
        var ${name} = class ${name} {} 
    `)

    console.log(Lorem) // class Lorem {}
}()

注意,它必须是var。在eval 中使用letconst 和普通class 将不起作用。

Function 的另一种方式:

~function() {
    const name = "Lorem"

    const c = new Function(`
        return class ${name} {}
    `)()

    console.log(c) // class Lorem {}
}()

Sitenote:您可以将范围变量传递到Function 并在内部使用它们:

~function() {
    const name = "Lorem"
    const val = "foo"

    const Class = new Function('val', `
        return class ${name} {
            constructor() {
                console.log( val )
            }
        }
    `)( val )

    console.log(Class) // class Lorem {}
    new Class // "foo"
}()

【讨论】:

  • 注意,这种方式使用Function也是eval,风险相同。
  • 只有在Functioneval 中粘贴第三方代码时才会出现问题。如果您拥有粘贴在那里的代码(例如,代码字符串是在与Functioneval 相同的范围内生成的,没有来自外部的输入),这不是问题。
  • @eyelidlessness 如果您将第 3 方代码粘贴在 Functioneval 中,这只是一个问题。如果您拥有粘贴在那里的代码(例如,代码字符串是在与Functioneval 相同的范围内生成的,没有来自外部的输入),这不是问题。正如您在我的示例中看到的那样,字符串是就地生成的,这是完全安全的(假设我的代码在模块内部,不可能从外部修改变量)。
  • 我已经更新了我的示例以使用闭包(很像模块)。
  • 仍然值得指出,因为人们倾向于获取代码示例并对其进行扩展。对于不太熟悉其工作原理的人来说,它使用eval 可能不会立即显而易见。我强烈建议您为此添加警告。
猜你喜欢
  • 1970-01-01
  • 2018-02-22
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
  • 2023-03-13
  • 1970-01-01
相关资源
最近更新 更多