Skip to content Skip to sidebar Skip to footer

How To Construct Javascript Object (using 'apply')?

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 Matth

Solution 1:

In ES5, you can do it via bind.

function construct(constructor, args) {
  return new (constructor.bind.apply(constructor, [null].concat(args)));
}

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

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. Let target be the value of F’s [[TargetFunction]] internal property.
  2. If target has no [[Construct]] internal method, a TypeError exception is thrown.
  3. Let boundArgs be the value of F’s [[BoundArgs]] internal property.
  4. Let args be a new list containing the same values as the list boundArgs in the same order followed by the same values as the list ExtraArgs in the same order.
  5. Return the result of calling the [[Construct]] internal method of target providing args as the arguments.

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;
}

Solution 2:

I may end up with this simplified version of Mike's triangle-of-hackery:

functionapplyCtor2(ctor, args) {
  switch (args.length) {
    case0: returnnewctor();
    case1: returnnewctor(args[0]);
    case2: returnnewctor(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 += ")";
  returneval(jsStr);
}

I'm not using 'apply' here, but I don't miss it. ;-) Any comments?

Post a Comment for "How To Construct Javascript Object (using 'apply')?"