Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何将字符串或类传递给方法以创建实例_Javascript_Typescript - Fatal编程技术网

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