【问题标题】:Create object from class name in JavasScript ECMAScript 6在 Javascript ECMAScript 6 中从类名创建对象
【发布时间】:2015-10-24 22:47:28
【问题描述】:

我想使用 ES6 创建对象工厂,但旧式语法不适用于 new。

我有下一个代码:

export class Column {}
export class Sequence {}
export class Checkbox {}

export class ColumnFactory {
    constructor() {
        this.specColumn = {
            __default: 'Column',
            __sequence: 'Sequence',
            __checkbox: 'Checkbox'
        };
    }

    create(name) {
        let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
        return new window[className](name); // this line throw error
    }
}

let factory = new ColumnFactory();
let column = factory.create('userName');

我做错了什么?

【问题讨论】:

  • 仅供参考,手动编码的 ES5 版本在这里工作:jsfiddle.net/jfriend00/4x45gqLt。可能值得看看 babeljs 产生了什么,看看有什么不同。显然 Column 不是全局的(因此不在 window 对象上),但生成的 ES5 代码肯定会显示给你。
  • 嗯,window[className] 从来没有可靠地工作过。

标签: javascript ecmascript-6 es6-class


【解决方案1】:

不要把类名放在那个对象上。将类本身放在那里,这样您就不必依赖它们是全局的并且可以通过window 访问(在浏览器中)。

顺便说一句,没有充分的理由让这个工厂成为一个类,你可能只会实例化它一次(单例)。让它成为一个对象:

export class Column {}
export class Sequence {}
export class Checkbox {}

export const columnFactory = {
    specColumn: {
        __default: Column,    // <--
        __sequence: Sequence, // <--
        __checkbox: Checkbox  // <--
    },
    create(name, ...args) {
        let cls = this.specColumn[name] || this.specColumn.__default;
        return new cls(...args);
    }
};

【讨论】:

  • 实际上很棒的工厂示例,在我的项目中使用它:)
【解决方案2】:

有一个小而肮脏的方法可以做到这一点:

function createClassByName(name,...a) {
    var c = eval(name);
    return new c(...a);
}

您现在可以像这样创建一个类:

let c = createClassByName( 'Person', x, y );

【讨论】:

  • 我喜欢这个评估解决方案
  • 我也是+1。我知道每个人都谴责 eval 但只要您完全控制可能的值,它就是最简单、最灵活的解决方案。
  • 我喜欢这个 eval,但现在有问题,无法在 es6 类方法中使用 eval 创建变量
  • 我认为使用 eval() developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 存在安全风险。
  • eval 太棒了
【解决方案3】:

问题是类不是窗口对象的属性。你可以有一个属性“指向”你的类的对象:

class Column {}
class Sequence {}
class Checkbox {}
let classes = {
  Column,
  Sequence,
  Checkbox 
}

class ColumnFactory {
    constructor() {
        this.specColumn = {
            __default: 'Column',
            __sequence: 'Sequence',
            __checkbox: 'Checkbox'
        };
    }

    create(name) {
        let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default'];
        return new classes[className](name); // this line no longer throw error
    }
}

let factory = new ColumnFactory();
let column = factory.create('userName');

export {ColumnFactory, Column, Sequence, Checkbox};

【讨论】:

  • Column 构造函数不是全局的吗?
  • 显然不在 babeljs 中(无法发布 repl,太长)
【解决方案4】:

对于那些不使用 ES6 并想知道如何使用字符串创建类的人来说,这是我为使其工作所做的工作。

"use strict";

class Person {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}
window.classes = {};
window.classes.Person = Person;

document.body.innerText = JSON.stringify(new window.classes["Person"](1, 2));

如您所见,最简单的方法是将类添加到对象中。

这是小提琴: https://jsfiddle.net/zxg7dsng/1/

这是一个使用这种方法的示例项目: https://github.com/pdxjohnny/dist-rts-client-web

【讨论】:

    【解决方案5】:

    我更喜欢这种方法:

    allThemClasses.js

    export class A {}
    export class B {}
    export class C {}
    

    script.js

    import * as Classes from './allThemClasses';
    
    const a = new Classes['A'];
    const b = new Classes['B'];
    const c = new Classes['C'];
    

    【讨论】:

      【解决方案6】:

      我知道这是一篇旧帖子,但最近我遇到了关于如何动态实例化类的相同问题

      我正在使用webpack,所以在documentation 之后,有一种方法可以使用 import() 函数动态加载模块

      js/classes/MyClass.js

      class MyClass {
          test = null;
          constructor(param) {
              console.log(param)
              this.test = param;
          }
      }
      

      js/app.js

      var p = "example";
      var className = "MyClass";
      
      import('./classes/'+className).then(function(mod) {
          let myClass = new mod[className](p);
          console.log(myClass);
      }, function(failMsg) {
          console.error("Fail to load class"+className);
          console.error(failMsg);
      });
      

      注意:此方法是异步的,我无法确定它的性能成本, 但它在我的简单程序上完美运行(值得一试^^)

      Ps顺便说一句,我是 Es6 的新手(几天),我更像是 C++/PHP/Java 开发人员。

      我希望这对遇到这个问题的人有所帮助,这不是一个坏习惯^^"。

      【讨论】:

        猜你喜欢
        • 2017-05-28
        • 2019-08-04
        • 2016-09-14
        • 1970-01-01
        • 2016-01-26
        • 2016-01-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多