ES6课程中的constr.apply(this,args)

Rem*_*sen 5 javascript oop constructor node.js ecmascript-6

我已经使用以下函数创建了一段时间未知类的实例:

Kernel.prototype._construct = function (constr, args) {
  function F() {
    constr.apply(this, args); // EXCEPTION!
  }
  F.prototype = constr.prototype;
  return new F();
};
Run Code Online (Sandbox Code Playgroud)

如果我使用原型,一切正常:

function Person(name, surname) {
  this.name = name;
  this.surname = surname;
}

var person = Kernel._construct(Person, ["name", "surname"]); // WORKS!
Run Code Online (Sandbox Code Playgroud)

但是,有些人在节点v4 +中使用我的库使用ES6本机类:

class Person {
  constructor(name, surname) {
    this.name = name;
    this.surname = surname;
  }
}

var person = Kernel._construct(Person, ["name", surname]); // EXCEPTION!
Run Code Online (Sandbox Code Playgroud)

他们收到一个错误:

TypeError: Class constructors cannot be invoked without 'new'
Run Code Online (Sandbox Code Playgroud)

我需要能够使用未知数量的参数调用构造函数.关于如何解决这个问题的任何想法?

Ami*_*mit 9

有多种方法可以做到这一点:

  1. 使用Function对象的方法:

    Kernel.prototype._construct = function (constr, args) {
      return new (Function.prototype.bind.apply(constr, [null].concat(args)));
    };
    
    Run Code Online (Sandbox Code Playgroud)

    在这里,我们申请 args作为参数bind.目标是拥有一个可以在没有调用的情况下调用的函数,以便我们可以调用new x().bind为我们这样做,但我们需要正确设置它.语法是:

    func.bind(thisArg[, arg1][, args2...])
    // calling the results from the above is like
    // thisArg.func(arg1, arg2...);
    
    Run Code Online (Sandbox Code Playgroud)

    我们希望将constr作为绑定的函数和args作为参数的项目用作.我们不在乎thisArg.为此,我们需要将args数组"转换" 为参数.该apply电话确实是:

    func.apply(thisArg[, args]);
    // calling the results from the above is like
    // thisArg.func(args[0], args[1]...);
    
    Run Code Online (Sandbox Code Playgroud)

    apply实际上是打电话bind.第一个项目,[null]因为我们要调用是非常重要的bind地方thisArgnull-这样的:constr.bind(null, args[0], args[1]...).

  2. 使用ES2015 Spread运算符:

    Kernel.prototype._construct = function (constr, args) {
      return new constr(...args);
    };
    
    Run Code Online (Sandbox Code Playgroud)

    这更简单,但有两个问题:

    1. 它需要ES2015支持,即使是最新的Node(v4.2.1)也需要一个标志(--harmony_spreadcalls).
    2. 如果不支持,这将生成语法错误,您甚至无法有条件地执行此操作,除此之外使用动态脚本(eval()/ new Function(...)) - 这是不建议的.
  3. 使用Reflect内置的对象.

    Kernel.prototype._construct = function (constr, args) {
        return Reflect.construct(constr, args);
    };
    
    Run Code Online (Sandbox Code Playgroud)

    这也很简单,但在支持方面甚至更落后(基本上你必须使用babel).