"not a Date object" vs. "not an object with [[Class]] of ''Date''"

Tom Van Cutsem tomvc.be at gmail.com
Fri Oct 1 21:30:27 PDT 2010


We have previously discussed the Proxy.create(handler, proto, className)
design and I think it's feasible. One issue is what should happen to the
proxy's [[ClassName]] when it becomes fixed. In the current design, a fixed
object proxy can be made indistinguishable from a regular object. That's no
longer the case if the fixed proxy should retain its custom [[ClassName]]
(which I think is desirable).

That said, if proxies would be able to virtualize something like
[[ClassName]], I think the array subclassing use case can be supported as
follows (I'm sure there's a much better way to do this, but this is just a
proof-of-concept):

function createArray(proto, initArray) {
  // proto is assumed to delegate to Array.prototype
  // initArray is assumed to be a real Array
  var handler = {
    get: function(r,n) {
      if (!initArray.hasOwnProperty(n)) {
        return proto[n];
      } else {
        return initArray[n];
      }
    },
    set: function(r,n,v) {
      return initArray[n] = v;
    },
    // other traps
  };
  return Proxy.create(handler, proto, "Array");
};

var SubArray = Object.create(Array.prototype);
SubArray.last = function() {
  return this[this.length - 1];
};

var myArray = createArray(SubArray, [1,2,3]);
myArray.length; // 3
myArray.last(); // 3
myArray[10] = 42;
myArray.length; // 11
myArray.last(); // 42
Object.prototype.toString.call(myArray); // [object Array]
myArray instanceof Array; // true
myArray.toString(); // 1,2,3,,,,,,,,42

I tested this in a recent tracemonkey shell with support for Proxies and it
seems to work (except that currently, of course, proxies cannot virtualize
[[ClassName]] so the proxy-array still prints as [object Object])

2010/10/1 Juriy Zaytsev <kangax.dev at gmail.com>

>
>
> On Fri, Oct 1, 2010 at 10:00 PM, Oliver Hunt <oliver at apple.com> wrote:
>
>>
>> On Oct 1, 2010, at 6:55 PM, Brendan Eich wrote:
>>
>> > On Oct 1, 2010, at 6:24 PM, Oliver Hunt wrote:
>> >
>> >> I really don't like the idea of using proxies simply to essentially
>> create an array with a custom prototype.
>> >
>> > Implement proxies, then we'll talk :-P.
>> >
>> >
>> >> My understanding of what is wanted (in terms of subtyping an array) is
>> an ability to have something like
>> >>
>> >> var arr = new MyArray()
>> >>
>> >> Where 'new MyArray' behaves in essentially the same manner as 'new
>> Array', however it produces an object along the lines of
>> >>
>> >> <an array instance> <- <a custom prototype> <- <array prototype>
>> >
>> > I don't think the use-case is satisfied by a direct Array instance,
>> whatever its proto. That's the rub.
>>
>> What part of the use case is not covered?  From reading the blog post
>> (which suggests something similar to this) kangax says the problem with this
>> solution is the use of the non-standard __proto__, not that it doesn't
>> achieve the desired result
>>
>
> Object.create([]) doesn't solve the problem of subclassing an array, since
> created object is still a plain Object object and so has [[Get]] and [[Put]]
> that act like Object's ones, not Array ones.
>
> var o = Object.create([]);
> o[2] = 'x';
> o.length; /* 0, not 3 as it should be */
>
> o.length = 0;
> o[2]; /* "x", not undefined as it should be */
>
> In ES3 (w/o extensions) you can't do much about it, but in ES5 it's
> possible to fiddle with length getter/setter to make object act like an
> array (the performance of such implementation turns out to be incredibly
> slow, for obvious reasons).
>
> So now when you solved "magic" length property (considering that we're in
> ES5), and have a plain Object object with [[Prototype]] referencing
> Array.prototype, you still have immutable [[Class]]. So Array.isArray would
> return false for this pseudo-array object (it could be somehow overwritten
> to account for it, but this is kind of getting too far); and then there are
> places in spec, where wrong [[Class]] ("Object", not "Array") will make for
> a completely different outcome. For example, JSON.stringify:
>
> var o = Object.create([]);
> o[2] = 'x';
>
> JSON.stringify(o); // "{"2":"x","length":0}" not [null,null,"x"]
>
> Settable [[Prototype]] helps because you can just create an array object,
> then inject something into its prototype chain (right before
> Array.prototype). And that extra object can have any methods you wish on
> subarray instances — all without polluting global Array.prototype.
>
> [...]
>
> --
> kangax
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20101001/7397d433/attachment.html>


More information about the es-discuss mailing list