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

时间:2015-10-18 01:09:39

标签: javascript node.js oop constructor ecmascript-6

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

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

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

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

var person = Kernel._construct(Person, ["name", "surname"]); // WORKS!

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

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

var person = Kernel._construct(Person, ["name", surname]); // EXCEPTION!

他们收到错误:

TypeError: Class constructors cannot be invoked without 'new'

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

3 个答案:

答案 0 :(得分:9)

您可以通过多种方式实现这一目标:

  1. 使用Function对象的方法:

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

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

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

    我们希望使用constr作为绑定函数,并使用args中的项作为参数。我们不关心thisArg。要做到这一点,我们需要"转换"参数的args数组。 apply调用会执行此操作:

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

    apply实际上正在调用bind。第一项[null]非常重要,因为我们想要bind thisArg null constr.bind(null, args[0], args[1]...),这样:Kernel.prototype._construct = function (constr, args) { return new constr(...args); };

  2. 使用ES2015 Spread operator

    eval()

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

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

    writetext

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

答案 1 :(得分:2)

你可以通过将参数绑定到函数然后在其上调用new来解决这个问题:

Kernel.prototype._construct = function (constr, args) {
  var F = constr.bind(null, args);
  return new F();
};

答案 2 :(得分:2)

很好的问题,但没有,根据ECMAScript §9.22,您无法在ES6中调用没有new关键字的构造函数。

我在这里问了一个相同的问题: ES6: call class constructor without new keyword

  

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

这没有说明(不)使用new关键字,但您可以在ES6构造函数中轻松使用可变参数

class Person {
  constructor(name, surname, ...others) {
    this.name = name;
    this.surname = surname;
    this.others = others || [];
  }
}

let p = new Person('OweR', 'ReLoaDeD', 'a', 'b', 'c');
p;
//=> {"name":"OweR","surname":"ReLoaDeD","others":["a","b","c"]}

我怀疑这不是你所追求的。但是,如果您试图避免使用new来调用ES6中的类,则无法完成。

所以,说到这一点,你究竟想要完成什么?