obsoleting the "new" keyword

Mark S. Miller erights at google.com
Sat Jan 24 21:54:52 PST 2009


On Sat, Jan 24, 2009 at 9:17 PM, Peter Michaux <petermichaux at gmail.com>wrote:

> As an idea, I just ran the following code in Firefox and it did do
> what I expected. It makes it possible to pass around a plain function
> object that will construct.
>
> Function.prototype.__defineGetter__("make", function() {
>  var thisC = this;
>  var F = function() {};
>  return function() {
>    F.prototype = thisC.prototype;
>    var o = new F();
>    thisC.apply(o, arguments);
>    return o;
>  };
> });


Won't work on Array, Date, RegExp, and Function, since o is created with
[[Class]] "Object". But should work otherwise.


> function Foo(a) {
>  this.a = a;
> }
> Foo.prototype.greet = function() {
>  alert('a foo says hello ' + this.a);
> };
>
> var f = Foo.make('a');
> f.greet();
>
> (function(con) {
>  var ff = con('asdf');
>  ff.greet();
> })(Foo.make);
>
>
> ------
>
> The above is not compatible with code written like the following
>
> function Foo() {
>  if (this instanceof Foo) {
>    //...
>  }
>  else {
>    //...
>  }
> }
>


Why not? I just tried it on FF and it seems to work fine.

> Is there a way to write "make" without using eval so that the
> constructor is called with an arbitrary number of arguments?

In Harmony you'll be able to use the "..." operator.

In ES3 and ES3.1, in order to handle Date, RegExp, and Array, the Cajita
runtime includes Mike Samuel's "triangle of hackery":

  /**
   * <tt>cajita.construct(ctor, [args...])</tt> invokes a simple function as
   * a constructor using 'new'.
   */
  function construct(ctor, args) {
    ctor = asCtor(ctor);
    // This works around problems with (new Array()) and (new Date()) where
    // the returned object is not really a Date or Array on SpiderMonkey and
    // other interpreters.
    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]);
      default:
        if (ctor.typeTag___ === 'Array') {
          return ctor.apply(USELESS, args);
        }
        var tmp = function tmp(args) {
          return ctor.apply(this, args);
        };
        tmp.prototype = ctor.prototype;
        return new tmp(args);
    }
  }

The last part is similar to your make method, and was inspired by Crock's
beget() pattern. Cajita does not whitelist the Function constructor. But for
full ES3 or ES3.1, since "new Function(..)" is equivalent to "Function(..)",
it would be easy to extend the triangle of hackery to handle the Function
constructor.

Fortunately, once we have "...", the triangle of hackery will become
unnecessary.

-- 
   Cheers,
   --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20090124/4db4028e/attachment-0001.html>


More information about the Es-discuss mailing list