如何构造 JavaScript 对象(使用“apply")? [英] How to construct JavaScript object (using 'apply')?

查看:18
本文介绍了如何构造 JavaScript 对象(使用“apply")?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种基于 (a) 构造函数的名称和 (b) 包含参数的数组来构造任意 JavaScript 对象的方法.我在 stackoverflow 的另一个线程中发现了这个函数(由 Matthew Crumley 编写?):

I'm looking for a way to construct arbitrary JavaScript objects based on (a) the name of the constructor, and (b) an array containing the arguments. I found this function (by Matthew Crumley ?) in an other thread on stackoverflow:

function construct(constructor, args) {
  function F() { return constructor.apply(this, args); }
  F.prototype = constructor.prototype;
  return new F();
}

这适用于用 JavaScript 编写的构造函数,但如果我尝试构造(日期,[...]),它会因类型错误而失败.我还不知道是否有更多的本机构造函数无法处理.我的问题是……

This works well with constructors written in JavaScript, but it fails with a TypeError if I try construct(Date, [...]). I don't know yet if there are more native constructors that this function can't handle. My questions are then ...

  • 较新版本的 JavaScript (ECMAScript 5) 中是否有可以解决我的问题的函数?
  • 如果没有,有什么方法可以检查有问题的构造函数,看看是否可以使用上述函数?(如果不能,我可能不得不使用 eval("new "+cname+"("+arglist+")").)

/乔恩

推荐答案

在 ES5 中,你可以通过 bind.

In ES5, you can do it via 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

which works because bind still uses the [[Construct]] abstract operator when the bound function appears to the right of new per http://es5.github.com/#x15.3.4.5.2 which says

当使用一个参数列表 ExtraArgs 调用函数对象的 [[Construct]] 内部方法时,使用 bind 函数创建的 F,执行以下步骤:

15.3.4.5.2 [[Construct]]

When the [[Construct]] internal method of a function object, F that was created using the bind function is called with a list of arguments ExtraArgs, the following steps are taken:

  1. 令 target 为 F 的 [[TargetFunction]] 内部属性的值.
  2. 如果目标没有 [[Construct]] 内部方法,则抛出 TypeError 异常.
  3. 令 boundArgs 为 F 的 [[BoundArgs]] 内部属性的值.
  4. 让 args 成为一个新列表,其中包含与列表 boundArgs 相同的值,其后跟与列表 ExtraArgs 相同的值.
  5. 返回调用 target 提供 args 作为参数的 [[Construct]] 内部方法的结果.

但是Function.prototype.bind 的大多数实现尝试将语言功能向后移植到 ES3 实现上,但无法正确处理用作构造函数的绑定函数,因此如果您不确定自己的代码在真正的 ES5 实现上运行,那么你必须回到黑客三角:

but most implementations of Function.prototype.bind that attempt to back-port the language feature onto ES3 implementations do not correctly handle bound functions used as a constructor, so if you're not sure your code is running on a real ES5 implementation then you have to fall back to the triangle of 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;
}

这篇关于如何构造 JavaScript 对象(使用“apply")?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆