如何使用动态数量的参数调用构造函数? [英] How to call a constructor with dynamic amount of arguments?
问题描述
我有一个构造函数,我不知道它需要的参数数量,例如:
I have a constructor and I don't know the number of arguments it needs, for instance:
function someCtor(a,b,c){
var that = this;
that.a = a;
that.b = b;
that.c = c;
}
我需要创建一个函数,该函数将返回该构造函数的实例动态数量的参数:
I need to create a function which will return the instance of that constructor with a dynamic amount of arguments:
function makeNew(ctor, arguments){
// this doesn't work, but it shows what I'm trying to achieve
return new ctor.apply(arguments);
}
我想使用该函数将动态参数传递给构造函数,如下所示:
I want to use the function to pass the dynamic arguments to the constructor like below:
var instanceOfCtor = makeNew(someCtor, [5,6,7]);
如何实现这个功能?
推荐答案
注意:请参阅最后的ES2015兼容性说明。
Note: See the ES2015 compatibility note at the end.
首先创建一个对象将其底层原型设置为对象构造函数上的 prototype
属性引用通过 Object.create
,然后调用构造函数通过函数#application
:
You do it by first creating an object setting its underlying prototype to the object the prototype
property on the constructor refers to via Object.create
, then calling the constructor via Function#apply
:
function makeNew(ctor, arguments){
var obj = Object.create(ctor.prototype);
var rv = ctor.apply(obj, arguments);
return rv && typeof rv === "object" ? rv : obj;
}
注意最后的一点点,所以我们正在模仿 new
运算符正确:当您通过 new
调用构造函数时,如果它返回非 null
对象引用,最终是 new
表达式的结果;如果它返回任何其他内容(或什么都没有),则由 new
创建的对象就是结果。所以我们模仿它。
Note the bit of fiddling at the end, so we're emulating the new
operator correctly: When you call a constructor via new
, if it returns a non-null
object reference, that ends up being the result of the new
expression; if it returns anything else (or nothing), the object created by new
is the result. So we emulate that.
即使在ES5之前的浏览器上,你也可以模仿足够的 Object.create
来做那个:
Even on pre-ES5 browsers, you can emulate enough of Object.create
to do that:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw new Error("The second argument of Object.create cannot be shimmed.");
}
function ctor() { }
ctor.prototype = proto;
return new ctor;
};
}
ES2015兼容性说明
如果您调用的构造函数是通过ES2015的 class
语法创建的,则上述操作无效,因为您可以这样称之为ES2015 class
构造函数。例如:
ES2015 Compatibility Note
If the constructor you're calling was created via ES2015's class
syntax, the above won't work, because you can't call ES2015 class
constructors that way. For example:
class Example {
constructor(a, b) {
this.a = a;
this.b = b;
}
}
const e = Object.create(Example.prototype);
Example.apply(e, [1, 2]); // TypeError: Class constructor Example cannot be invoked without 'new' (or similar)
好消息是只会在ES2015 +兼容的JavaScript引擎上发生,并且只有构造函数是通过 class
创建的;坏消息是它可能会发生。
The good news is that will only happen on an ES2015+-compatible JavaScript engine, and only if the constructor was created via class
; the bad news is that it can happen.
那么如何让你的 makeNew
防弹?
事实证明这很容易,因为ES2015还添加了 Reflect.construct
,这正是你想要的 makeNew
要做但是以与 class
构造函数和函数$ c $兼容的方式执行c>构造函数。因此,您可以使用功能检测
Reflect.construct
并使用它(如果存在)(ES2015 JavaScript引擎,因此可能已使用类创建构造函数
)并且如果它不存在则回退到上面(ES2015之前的引擎,将不会有任何类
构造函数):
It turns out this is quite easy, because ES2015 also added Reflect.construct
, which does exactly what you want makeNew
to do but does it in a way that's compatible with both class
constructors and function
constructors. So you can feature-detect Reflect.construct
and use it if it's present (ES2015 JavaScript engine, so a constructor might have been created with class
) and fall back to the above if it's not there (pre-ES2015 engine, there won't be any class
constructors around):
var makeNew; // `var` because we have to avoid any ES2015+ syntax
if (typeof Reflect === "object" && Reflect && typeof Reflect.construct === "function") {
// This is an ES2015-compatible JavaScript engine, use `Reflect.construct`
makeNew = Reflect.construct;
} else {
makeNew = function makeNew(ctor, arguments){
var obj = Object.create(ctor.prototype);
var rv = ctor.apply(obj, arguments);
return rv && typeof rv === "object" ? rv : obj;
};
}
这是纯ES5语法,所以在ES5引擎上运行,但使用的是ES2015的 Reflect.construct
如果它存在。
That's pure ES5 syntax, so runs on ES5 engines, but uses ES2015's Reflect.construct
if it's present.
这篇关于如何使用动态数量的参数调用构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!