使用动态名称在 ES6 中创建类的实例?

IT技术 javascript class dynamic ecmascript-6
2021-02-11 15:13:00

我希望能够通过将字符串变量传递给函数来实例化特定的 ES6 类。根据变量的值,将创建不同的类。

示例- 我有 2 个类,ClassOne, ClassTwo我希望能够将变量传递给函数并返回一个新类。类的名称将与变量相关 - 例如。传递'Two'将创建ClassTwo.

希望只用一个switch条款是这样的:

function createRelevantClass( desiredSubclassName )
{
  let args = [],
      newClass;

  switch( desiredSubclassName )
  {
    case 'One' :
      newClass = new ClassOne(args);
      break;
    case 'Two' :
      newClass = new ClassTwo(args);
      break;
  }

  return newClass;
}

相反,我希望能够以某种方式使用变量名创建构造函数调用。那可能吗?

function createRelevantClass( desiredSubclassName )
{
  // desiredSubclassName would be string 'One' or 'Two'

  // how to use the 'new' operator or Reflect here to create the class based on the variable passed in
  let newClass = ( *magic code to build constructor dynamically* );

  return newClass;
}
2个回答

有几种方法可以实现这一点......

1.代理类

遵循@thefourtheye 维护名称到类的映射的示例,您可以拥有一个类,其工作是获取所需类的名称并代理其实例化:

[看到它工作]

定义你的类

// ClassOne.js
export class ClassOne {
    constructor () {
        console.log("Hi from ClassOne");
    }
}

// ClassTwo.js
export class ClassTwo {
    constructor (msg) {
        console.log(`${msg} from ClassTwo`);
    }
}

定义代理类(例如DynamicClass

import ClassOne from './ClassOne';
import ClassTwo from './ClassTwo';

// Use ES6 Object Literal Property Value Shorthand to maintain a map
// where the keys share the same names as the classes themselves
const classes = {
    ClassOne,
    ClassTwo
};

class DynamicClass {
    constructor (className, opts) {
        return new classes[className](opts);
    }
}

export default DynamicClass;

示例用法

import DynamicClass from './DynamicClass';

new DynamicClass('ClassOne'); //=> "Hi from ClassOne"
new DynamicClass('ClassTwo', 'Bye'); //=> "Bye from ClassTwo"

2. 工厂​​功能

使用一个函数对类名的对象执行查找 -> 类映射并返回对类的引用,然后我们可以像往常一样实例化。

定义工厂函数

import ClassOne from './ClassOne';
import ClassTwo from './ClassTwo';

const classes = { ClassOne, ClassTwo };

export default function dynamicClass (name) {
  return classes[name];
}

示例用法

import dynamicClass from './dynamicClass'

const ClassOne = dynamicClass('ClassOne') // Get the ClassOne class

new ClassOne(args) // Create an instance of ClassOne
我不同意这种做法。返回值不应该是一个类,而应该是工厂请求的类的对象。请查看以下链接:en.wikipedia.org/wiki/Factory_method_pattern
2021-03-18 15:13:00
最后我将两者结合起来 - 一个简单的工厂函数,它使用类引用的非映射常量。感谢您的大力帮助。
2021-04-02 15:13:00
它实际上不必是一个类。它可以是一个简单的工厂函数。恕我直言,一个class有点矫枉过正。
2021-04-04 15:13:00
我喜欢这个,因为我不必显式地构建变量到类的映射——只要有一个常量和要构造的类组就足够了。@thefourtheye 的例子很简洁,但我认为这更接近我想要做的。
2021-04-08 15:13:00
如果您有一个包含许多类的库,并且类的数量和名称会不时更改,这不是很方便。每次更新都必须将新类的名称添加到代理中。
2021-04-12 15:13:00

将类存储在一个对象中,键是您希望它们成为的类的名称。

const classesMapping = {
  'One': ClassOne,
  'Two': ClassTwo
};

然后根据这样的键名创建类

return new classesMapping[desiredSubclassName](args);
大开眼界..谢谢!但是如果desiredSubclassName 实际上已经与类名相同怎么办?将“ClassOne”映射到 ClassOne 对我来说似乎有点多余。我很感激任何建议。
2021-03-23 15:13:00
@bertie 如果您使用的是 ES6,则有可能。有一个快捷方式 { 'Foo' : Foo } 可以写成 { Foo }
2021-04-02 15:13:00
谢谢。经过深思熟虑,它会作为module必须在某个阶段导入,例如plnkr.co/edit/luvxe81sIHQSwIyGwBdC?p=preview
2021-04-05 15:13:00
@RGraham 哦,那个网站看起来不错 :-) 谢谢 :-)
2021-04-06 15:13:00
@RGraham 不。不必要。
2021-04-10 15:13:00