Why doesn't Array.from() pass the array to the mapFn?

# the kojoman (7 years ago)

Array.map(mapFn) calls the mapFn(v,i,a) passing the currentValue, currentIndex and the array it is iterating over as arguments. I was happy to find out about Array.from(itterable, mapFn, thisArg), but unfortunately, the mapping didn't work as expected. It seems, Array.from doesn't pass in the newly created array to the mapFn. Why is that?

For instance I was expecting Array.from("aabc", (v,i,a) => { if(a[i] ===

a[i-1]) a.splice(i,1) }) to evaluate to ["a","b","c"], but a is undefined. Is there a reason why the mapFn isn't called the same way as an Array.map function is?

# T.J. Crowder (7 years ago)

Array.prototype.map doesn't pass a reference to the newly-created array either. The third argument Array.prototype.map passes the mapping function is a reference to the existing array, not the new one. With Array.from, there is no existing array to pass.

Not having the mapping functions (either of them) get a reference to the array being constructed avoids an entire class of errors caused by the mapping function modifying the array as it's being constructed.

-- T.J. Crowder

# the kojoman (7 years ago)

Thanks for the clarification. I thought the mapping was applied afterwards.

I would still argue that it would be better to skip it all together than having it and not working like the existing map function. So Array.from(array-like).map(mapFn) is the way to go then? ons 3 maj 2017 kl. 13:06 skrev T.J. Crowder <tj.crowder at farsightsoftware.com

# T.J. Crowder (7 years ago)

On Wed, May 3, 2017 at 12:39 PM, the kojoman <kojoman at gmail.com> wrote:

Thanks for the clarification. I thought the mapping was applied afterwards.

I would still argue that it would be better to skip it all together than having it and not working like the existing map function.

So Array.from(array-like).map(mapFn) is the way to go then?

Why make two passes over the contents rather than just one?

It is interesting that Array.from doesn't pass its first parameter (items, the source object) as the third argument to the mapping function. I suspect it's because the index doesn't necessarily work with the source object, if an iterator is being used...

-- T.J. Crowder

# Jordan Harband (7 years ago)

I think what you're looking for is map + filter - mutating the list mid-iteration is very bad news bears.

In other words, Array.from(arrayLike, mapFn).filter(removeWhatever)

# Jordan Harband (7 years ago)

(an index in Array.from wouldn't make sense, because Array.from takes an iterable or an arraylike - and only an arraylike would be guaranteed to have an index, or even a "list" at all)

# T.J. Crowder (7 years ago)

On Wed, May 3, 2017 at 7:35 PM, Jordan Harband <ljharb at gmail.com> wrote:

(an index in Array.from wouldn't make sense, because Array.from takes an iterable or an arraylike - and only an arraylike would be guaranteed to have an index, or even a "list" at all)

And yet, it provides one. It's the index that will be used to set the array entry from the result. It's only the third argument (the source object) that Array.from doesn't include.

-- T.J. Crowder

# Jordan Harband (7 years ago)

Good point :-) i guess as the destination index it makes sense, altho i've always thought of it as the source index.

# the kojoman (7 years ago)

Thanks Jordan, filter was, of course, what I was looking for. Just got carried away, when I saw it had a mapFn as an option and thought I could use that somehow to cut a corner. By the way, and kind of off topic, why is mutating a list mid-iteration bad news? I'm just curious, and obviously not a computer engineer.

ons 3 maj 2017 kl 23:37 skrev Jordan Harband <ljharb at gmail.com>:

# Ben Katz (7 years ago)

I have a couple ideas why:

  1. It discourages separation of concerns - cloning/filtering/mapping...
  2. Iterables can change mid iteration. Better to make the clone process as atomic as possible.