我一直在尝试 ES6 类,想知道是否可以动态更改类名?例如
class [Some dynamic name] {};
let C = class
{ // ...
}
Object.defineProperty (C, 'name', {value: 'TheName'});
// test:
let itsName = (new C()).constructor.name;
// itsName === 'TheName' -> true
有一个非常简单的方法:
const nameIt = (name, cls) => ({[name] : class extends cls {}})[name];
这里是演示。
它使用对象文字来定义具有所需名称的字段,该字段将保存新类。这会导致新类自动获取所需的名称。完成后,我们提取新类并返回它。
请注意对象文字周围的括号,这样大括号就不会被误认为是代码块
(...) => {...}
。
当然,将现有类放入命名字段不会更改该类,因此只有在创建新类时这才有效。如果您只需要在定义要命名的类的地方使用动态名称,则可以删除额外的继承,然后继续:
const myClass = {[name]: class {
...
}}[name];
对于您想要实现的目标,可能有更好的解决方案,但是您可以将类表达式分配给对象:
let classes = {};
classes[someName] = class { ... };
这在 ES2015 中并没有真正改变:如果你想创建动态命名的绑定,你必须使用对象或其他映射。
为了进一步玩动态类名和动态继承,当使用 babel 时,你可以这样做:
function withname(name, _parent) {
return class MyDinamicallyNamedClass extends (_parent||Object) {
static get name() { return name || _parent.name }
}
}
一种方法,即使不理想,也很简单
eval
:
~function() {
const name = "Lorem"
eval(`
var ${name} = class ${name} {}
`)
console.log(Lorem) // class Lorem {}
}()
注意,必须与
var
。在 let
内使用 const
、class
和普通 eval
不起作用。
另一种方式
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"
}()
我可以建议另一种方法,只是异步,但它有效:
let protoExtend = function ( className, extendsFrom = Array ) {
return new Promise( function ( done, fail ) {
const src = URL.createObjectURL(
new Blob( [`
self.${className}(
class ${className} extends ${extendsFrom.name} {}
);`
] )
);
self[ className ] = function ( prototype ){
URL.revokeObjectURL(src);
delete self[ className ];
return done( prototype );
};
document.head.append( Object.assign(
document.createElement("script"), { src }
));
});
};
使用父类和新子类的名称触发类构造函数:
let myClass = await protoExtend("HelloWorld", String);
现在我们有了我们想要的:动态创建的子级,无需任何评估:
new myClass('test');