Javascript 如何将字符串或类传递给方法以创建实例
我将使用以下方法,它通过向其传递一个类型来工作,例如Javascript 如何将字符串或类传递给方法以创建实例,javascript,typescript,Javascript,Typescript,我将使用以下方法,它通过向其传递一个类型来工作,例如obj.addComponent(MyClass)。这个很好用 我试图通过添加|string来修改类型参数,但现在它给我的错误是: 无法将“new”与类型缺少调用或构造签名的表达式一起使用 我是否可以修改它,以便在类中传递类名或字符串版本 以下是我所拥有的不起作用的东西: public addComponent<T extends Component>(type: ComponentType<T> | string):
obj.addComponent(MyClass)
。这个很好用
我试图通过添加|string
来修改类型
参数,但现在它给我的错误是:
无法将“new”与类型缺少调用或构造签名的表达式一起使用
我是否可以修改它,以便在类中传递类名或字符串版本
以下是我所拥有的不起作用的东西:
public addComponent<T extends Component>(type: ComponentType<T> | string): T {
let comp;
comp = new type() as T;
comp.name = comp.constructor.name;
}
或
在javascript中无法使用名称获取类,因为它没有类似于java
类加载器的东西
您可以通过创建自己的机制来解决这个问题,可能有很多方法,但这里有3个选项
(1) 维护组件类的注册表:
const REGISTRY: { [name: string]: ComponentType<Component> } = {};
class Component {}
class MyComponent1 extends Component {}
REGISTRY["MyComponent1"] = MyComponent1;
class MyComponent2 extends Component {}
REGISTRY["MyComponent2"] = MyComponent2;
type ComponentType<T extends Component> = {
new(): T;
}
function factory<T extends Component>(type: ComponentType<T> | string): T {
return typeof type === "string" ?
new REGISTRY[type]() as T:
new type();
}
()
(2) 将组件包装到命名空间中(如@Shilly在注释中所建议的):
命名空间组件{
导出类组件{}
导出类MyComponent1扩展组件{}
导出类MyComponent2扩展组件{}
导出类型ComponentType={
新的():T;
}
导出函数forName(名称:字符串):ComponentType{
if(this[name]&&this[name].prototype组件实例){
返回此[名称];
}
}
}
函数工厂(类型:components.ComponentType |字符串):T{
返回typeof type==“string”?
新的(components.forName(type))()作为T:
新类型();
}
()
如果使用这种方法,则需要确保导出所有组件类
(3) 使用eval
类组件{}
类MyComponent1扩展组件{}
类MyComponent2扩展组件{}
类型组件类型={
新的():T;
}
函数工厂(类型:ComponentType |字符串):T{
返回typeof type==“string”?
新的(eval(type))()作为T:
新类型();
}
()
这不是推荐的方法,您可以在许多地方使用eval
。
但它仍然是一个选项,所以我将其列出。如果类位于名称空间中,有一种方法可以将它们的名称实例化为字符串:
var variableName: any = new YourNamespace[YourClassNameString](ClassParameters);
对于exmaple,这应该是可行的:
namespace myNamespace {
export class myClass {
example() {
return true;
}
}
}
var newClass: any = new myNamespace["myClass"](); // <- This loads the class A.
newClass.example();
然后,您将能够执行以下操作:
let stringToLoad = "Component";
let classToLoad = Component;
let example = new Example();
let result1: Component = example.addComponent(stringToLoad);
let result2: Component = example.addComponent(classToLoad);
带有代码+测试的游乐场版本:由于基本上使用的是新类型()
,因此必须更改该部分。如果所有“类”共享一个命名空间,则如果类型是对象,则可以使用当前版本;如果类型是字符串,则可以使用new namespace[type]
。传入的值不使用命名空间。我不确定您在问什么。您想知道如何通过字符串名实例化类吗?是的,或者通过传递类。让我更新一下这个例子…@NitzanTomer我已经用一个例子更新了我最初的帖子,说明了我想如何使用这个方法。例子3似乎是最有活力的。但是,我正在删除所有不是字母数字或下划线的字符,let evalT=type.replace(/[^a-zA-Z0-9\]/g')代码>然后我将该结果传递给eval。我更喜欢装饰程序的第一个,它易于使用且健壮。使用eval
时可能会出错。使用名称空间似乎无法按我希望的方式工作。不过,这确实有效,只是不是以我希望的方式。我很难让它运行。不能让上面的操场正常工作。请参阅本帖:
function register(constructor: typeof Component) {
REGISTRY[(constructor as any).name] = constructor;
}
@register
class MyComponent1 extends Component {}
@register
class MyComponent2 extends Component {}
namespace components {
export class Component {}
export class MyComponent1 extends Component {}
export class MyComponent2 extends Component {}
export type ComponentType<T extends Component> = {
new(): T;
}
export function forName(name: string): ComponentType<Component> {
if (this[name] && this[name].prototype instanceof Component) {
return this[name];
}
}
}
function factory<T extends components.Component>(type: components.ComponentType<T> | string): T {
return typeof type === "string" ?
new (components.forName(type))() as T:
new type();
}
class Component {}
class MyComponent1 extends Component {}
class MyComponent2 extends Component {}
type ComponentType<T extends Component> = {
new(): T;
}
function factory<T extends Component>(type: ComponentType<T> | string): T {
return typeof type === "string" ?
new (eval(type))() as T:
new type();
}
var variableName: any = new YourNamespace[YourClassNameString](ClassParameters);
namespace myNamespace {
export class myClass {
example() {
return true;
}
}
}
var newClass: any = new myNamespace["myClass"](); // <- This loads the class A.
newClass.example();
namespace myNamespace {
// The dependencies you defined
export class Component {
}
export interface ComponentType<T extends Component> {
new(): T;
}
// Just a class to contain the method's code
export class Example {
public addComponent<T extends Component>(type: ComponentType<T> | string): T {
let result: T;
if (typeof type === "string") {
result = new myNamespace[type]();
} else {
result = new type();
}
return result;
}
}
}
let stringToLoad = "Component";
let classToLoad = Component;
let example = new Example();
let result1: Component = example.addComponent(stringToLoad);
let result2: Component = example.addComponent(classToLoad);