一段时间以来,我一直在使用以下函数来创建未知类的实例:
Kernel.prototype._construct = function (constr, args) {
function F() {
constr.apply(this, args); // EXCEPTION!
}
F.prototype = constr.prototype;
return new F();
};
如果我使用原型(prototype),一切正常:
function Person(name, surname) {
this.name = name;
this.surname = surname;
}
var person = Kernel._construct(Person, ["name", "surname"]); // WORKS!
但是,有些人在 Node 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'
我需要能够使用未知数量的参数调用构造函数。关于如何解决此问题的任何想法?
最佳答案
有多种方法可以做到这一点:
使用
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
作为绑定(bind)函数,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]...)
。使用 ES2015 Spread operator :
Kernel.prototype._construct = function (constr, args) { return new constr(...args); };
这样就简单多了,但是有两个问题:
- 它需要 ES2015 支持,甚至最新的 Node (v4.2.1) 也需要一个标志 (--harmony_spreadcalls)。
- 如果不支持,这将产生语法错误,您甚至不能有条件地这样做,除非使用动态脚本 (
eval()
/new Function(...)
) - 不建议这样做。
使用
Reflect
内置对象。Kernel.prototype._construct = function (constr, args) { return Reflect.construct(constr, args); };
这也很简单,但在支持方面更落后(基本上你必须使用 babel)。
关于javascript - ES6 类中的 constr.apply(this, args),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33193310/