Why does Array.from also take a mapFn?

Allen Wirfs-Brock allen at wirfs-brock.com
Mon Jun 24 17:45:35 PDT 2013


On Jun 24, 2013, at 5:21 PM, Dmitry Soshnikov wrote:

> 
> On Mon, Jun 24, 2013 at 9:31 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
> 
> On Jun 24, 2013, at 8:42 AM, Jason Orendorff wrote:
> 
> > According to the January 30 meeting notes, Array.from is getting
> > optional map functionality.[1]
> >
> > This is motivated by the following example:
> >
> >    class V extends Array {
> >        constructor(...args) {
> >            super(...args);
> >        }
> >    }
> >
> >    var v, m;
> >    v = new V(1, 2, 3);
> >    m = v.map(val => val * 2);
> >    console.log( m instanceof V ); // false :(
> >
> > Of course changing Array.from doesn't fix this; v.map() still returns
> > an Array, same as before. And there was already an easy workaround:
> >    m = V.from(v.map(val => val * 2));
> 
> The issues (and discussion) is more complex then the above indicates.
> 
> The root issue concerns what should Array producing methods such as Map produce when used in an Array subclass. Should the result be an Array instance (as it currently is in ES5) or should it be a new instance of the subclass.  If the latter, how is the actual subclass determined.
> 
> If the `map` method is inherited and is called directly on the instance of the inherited class, then probably it's more logical to return the instance of the same inheriting class (i.e. the V).
> 
> To answer your question how the determination of the subclass should happen -- first need to ask what is the [[NativeBrand]] says for "v" instance? Is it still "NativeArray" (shouldn't be IMO, will clarify in the spec later)?
> 
> Can you use the [[NativeBrand]] check or at very least `constrcutor` property check (which though, not that safe maybe). Will it actually make sense to set the [[NativeBrand]] to the name of the class?
> 
> if (Array.isArray(this)) {
>   var result = [];
> } else {
>   var result = new this.constructor(<somehow_get_the_default_args>?);
> }
> 
> But again there is an issue with determination of the default arguments of the constructor, though can fallback to defaults.

[[NativeBrand]] is long gone and regardless won't apply to all subclasses.

Here is how it is currently spec'ed in Array.of and Array.from:

	• 1.	If IsConstructor(C) is true, then
		• a.	Let newObj be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
		• b.	Let A be ToObject(newObj).
	• 2.	Else,
		• a.	Let A be the result of the abstract operation ArrayCreate with argument len.



while is pretty much equivalent to:
class Array extends Object {
   constructor(...args) {
      ...
    }
    of(...args) {
        let len = args.length;
        let a;
        if (isConstructor(this)) a = new this(len);
        else a = new Array(len(
        ...
      }
...
}
    
In the spec I have a note that it would be better if there was a more explicitly specified way to allocate an empty collection object (of any kind) with a parameterized number of elements.   The current spec. for Array.of/from works with any constructor that treats a single numeric argument new call as such a request.

Allen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130624/76907156/attachment.html>


More information about the es-discuss mailing list