繁体   English   中英

如何构造JavaScript对象(使用'apply')?

[英]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而失败。 我还不知道是否有更多的本机构造函数,这个函数无法处理。 我的问题是......

  • 是否有更新版本的JavaScript(ECMAScript 5)中的函数可以解决我的问题?
  • 如果没有,是否有某种方法可以检查有问题的构造函数,看看是否可以使用上述函数? (如果不能,我可能必须使用eval(“new”+ cname +“(”+ arglist +“)”)。)

/乔恩

在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调用时,将执行以下步骤:

  1. 设目标是F的[[TargetFunction]]内部属性的值。
  2. 如果target没有[[Construct]]内部方法,则抛出TypeError异常。
  3. 设boundArgs为F [[BoundArgs]]内部属性的值。
  4. 让args成为一个新列表,其中包含与列表boundArgs相同的值,顺序相同,后面跟相同顺序的列表ExtraArgs相同。
  5. 返回调用[[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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM