[英]How to construct JavaScript object (using 'apply')?
我正在寻找一种基于(a)构造函数的名称构造任意JavaScript对象的方法,以及(b)包含参数的数组。 我在stackoverflow上的另一个线程中发现了这个函数(由Matthew Crumley撰写?):
function construct(constructor, args) {
function F() { return constructor.apply(this, args); }
F.prototype = constructor.prototype;
return new F();
}
这适用于用JavaScript编写的构造函数,但如果我尝试构造(Date,[...])则它会因TypeError而失败。 我还不知道是否有更多的本机构造函数,这个函数无法处理。 我的问题是......
/乔恩
在ES5中,您可以通过bind
。
function construct(constructor, args) {
return new (constructor.bind.apply(constructor, [null].concat(args)));
}
这是有效的,因为bind
仍然使用[[Construct]]抽象运算符当绑定函数出现在new
的右侧时每http://es5.github.com/#x15.3.4.5.2
15.3.4.5.2 [[Construct]]
当使用
bind
函数创建的函数对象的[[Construct]]内部方法,使用参数列表ExtraArgs调用时,将执行以下步骤:
- 设目标是F的[[TargetFunction]]内部属性的值。
- 如果target没有[[Construct]]内部方法,则抛出TypeError异常。
- 设boundArgs为F [[BoundArgs]]内部属性的值。
- 让args成为一个新列表,其中包含与列表boundArgs相同的值,顺序相同,后面跟相同顺序的列表ExtraArgs相同。
- 返回调用[[Construct]]目标的内部方法的结果,提供args作为参数。
但是大多数尝试将语言功能反向移植到ES3实现上的Function.prototype.bind
实现都没有正确处理用作构造函数的绑定函数,所以如果你不确定你的代码是在真正的ES5实现上运行那么你必须回到hackery的三角形:
function applyCtor(ctor, args) {
// Triangle of hackery which handles host object constructors and intrinsics.
// Warning: The goggles! They do nothing!
switch (args.length) {
case 0: return new ctor;
case 1: return new ctor(args[0]);
case 2: return new ctor(args[0], args[1]);
case 3: return new ctor(args[0], args[1], args[2]);
case 4: return new ctor(args[0], args[1], args[2], args[3]);
case 5: return new ctor(args[0], args[1], args[2], args[3], args[4]);
case 6: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
case 7: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case 8: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
case 9: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
case 10: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
case 11: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
case 12: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
}
// End triangle of hackery
// Create a throwaway subclass of ctor whose constructor does nothing.
function TemporarySubclass() {}
TemporarySubclass.prototype = ctor.prototype;
var instance = new TemporarySubclass();
instance.constructor = ctor; // Patch constructor property
// Run the constructor. This assumes that [[Call]] internal method is the same as
// [[Construct]]. It might work with some builtins/host objects where "new` would not.
var returnValue = ctor.apply(instance, args);
// If the constructor returned a non-primitive value, return it instead.
switch (typeof returnValue) {
case 'object':
// If ctor is Array, it reaches here so we don't use broken Array subclass.
// Ditto for Date.
if (returnValue) { return returnValue; }
break;
case 'function':
return returnValue;
}
// Return the constructed instance.
return instance;
}
我最终可能会得到Mike的三角形简化版:
function applyCtor2(ctor, args) {
switch (args.length) {
case 0: return new ctor();
case 1: return new ctor(args[0]);
case 2: return new ctor(args[0], args[1]);
// add more cases if you like
}
var jsStr = "new ctor(args[0]";
for (var i=1; i<ar.length; i++) jsStr += ",args[" + i + "]";
jsStr += ")";
return eval(jsStr);
}
我不是在这里使用'申请',但我不会错过它。 ;-) 任何意见?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.