如何将字符串或类传递给方法来创建实例 [英] How to pass a string or class to a method to create instance

查看:52
本文介绍了如何将字符串或类传递给方法来创建实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将使用以下方法,它通过将类型传递给它来工作,例如 obj.addComponent(MyClass)。这很好用。

I am to use the following method, it works by passing a type to it such as obj.addComponent(MyClass). This works just fine.

我尝试通过添加 |来修改类型参数字符串,但它现在给我错误说:

I tried to modify the type parameter by adding | string to it, but it now gives me errors saying:


不能对表达式使用'new' type缺少一个调用或构造签名。

Cannot use 'new' with an expression whose type lacks a call or construct signature.

我是否仍然要修改它以便我可以传递一个类名或者该类的字符串版本?

Is there anyway for me to modify this so that I can pass either a Class name in or a string version of the class?

这是我的不起作用:

public addComponent<T extends Component>(type: ComponentType<T> | string): T {
    let comp;
    comp = new type() as T;
    comp.name = comp.constructor.name;
}

以下是它的依赖关系:

class Component extends Obj {

}

interface ComponentType<T extends Component> {
    new(): T;
}

我尝试过使用 Object.create(),它工作正常,但后来我收到一个新错误:

I have tried using Object.create(), which works fine, but then I get a new error:


未捕获的TypeError:无法分配给只读属性对象'[对象]'的'名称'

Uncaught TypeError: Cannot assign to read only property 'name' of object '[object Object]'

编辑:

最后我希望能够将以下内容传递给 addComponent

In the end I would like to be able to pass the following to addComponent:

obj.addComponent(MyClass);

obj.addComponent("MyClass");


推荐答案

没有办法让类使用名称javascript,它没有类似java ClassLoader 的东西。

您可以通过创建自己的机制来解决这个问题,并且可能有很多方法这样做,但这里有3个选项。

There's no way to get the class using a name in javascript, it doesn't have something similar to the java ClassLoader.
You can get around that by creating your own mechanism, and there are probably many ways to do so, but here are 3 options.

(1)维护组件类的注册表:

(1) Maintain a registry for your component classes:

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();
}

操场上的代码

如果你采用这种方法,那么我建议你做 REGISTRY 一个包含集合的对象,这样你就可以只添加ctor并从中获取名称。

If you go with this approach then I suggest to make the REGISTRY an object that holds the collection, that way you can add the ctor only and get the name from that.

这里有一个变体,就是使用装饰器: / p>

There's a variant for this and that's to use a decorator:

function register(constructor: typeof Component) {
    REGISTRY[(constructor as any).name] = constructor;
}

@register
class MyComponent1 extends Component {}

@register
class MyComponent2 extends Component {}

游乐场代码

(2)将组件包装在命名空间中(正如@Shilly在评论中建议的那样):

(2) Wrap the components in a namespace (As @Shilly suggested in a comment):

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();
}

操场上的代码

如果你采用这种方法,那么你需要确保所有导出组件类。

If you're going with this approach then you need to make sure that all the component classes are exported.

(3)使用eval

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();
}

操场上的代码

这不是推荐的方法,你可以在许多地方使用 eval 阅读所有关于利弊

但它仍然是一个选项所以我正在列出它。

This isn't a recommended approach, and you can read all about the cons in using eval in a lot of places.
But it's still an option so I'm listing it.

这篇关于如何将字符串或类传递给方法来创建实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆