1

I am trying to concat an arguments object with another array, and I wrote code like this:

[].concat.call(arguments, newArray)

But it returns [ [object Arguments], ... ], that is exactly not what I want. I googled and found some explanations for why I could do this through slice method: How can I convert the "arguments" object to an array in JavaScript?

But after looked up the spec, I found the same definition on concat method:

NOTE The concat function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the concat function can be applied successfully to a host object is implementation-dependent.

The spec is here: http://es5.github.io/#x15.4.4.4

So now I am confusing why I can't convert the arguments object to an array through the concat method.

Community
  • 1
  • 1
Dolphin_Wood
  • 847
  • 5
  • 19
  • *"and I wrote code like this"* What's `newArray`? – T.J. Crowder Apr 04 '15 at 12:44
  • Look at steps 5b and 5c. That's why. The note seems to diverge from the algorithm., but notes are explictly informal. – Felix Kling Apr 04 '15 at 12:48
  • That's another array like `[ 1, 2, 3 ]`. – Dolphin_Wood Apr 04 '15 at 12:49
  • 1
    This has changed in ES6 btw (at least theoretically):: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-array-prototype-object – Felix Kling Apr 04 '15 at 12:52
  • @FelixKling: I see the concat-spreadable thing, but I don't see where the spec says that `arguments` has that flag. Am I just missing it? – T.J. Crowder Apr 04 '15 at 12:58
  • 1
    @T.J.Crowder: that's why I added "theoretically". At least it doesn't restrict it to arrays anymore, unless arrays are the only thing that implement that property :-/ which could very well be, now that I'm thinking about it, since changing this would break backwards compatibility? – Felix Kling Apr 04 '15 at 13:01
  • @FelixKling: Yeah, that's probably why. – T.J. Crowder Apr 04 '15 at 13:01
  • @FelixKling: No it has not? `arguments` objects don't have `@@isConcatSpreadable` set (no spec object seems to at all), and they're arrays neither. You can do `Array.from(arguments).concat(newArray)`, though. – Bergi Apr 04 '15 at 13:05
  • @Bergi: yeah, I should have been more clear. I meant that the implementation changed and can now also deal with objects that are not arrays (and treat them as if they were arrays). – Felix Kling Apr 04 '15 at 13:06

1 Answers1

2

The details can be found in §15.4.4.4 of the spec. Basically, it starts out by creating a list of things to process, where the first item on the list is the the object you called it on (this) and then subsequent items on the list are the arguments to the function. Then it loops through the list and processes each item. It has an explicit branch in it for items on that list that aren't arrays, and the "else" of that branch is (Step 5(c)):

  • Else, E is not an Array
    • Call the [[DefineOwnProperty]] internal method of A with arguments ToString(n), Property Descriptor {[[Value]]: E, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    • Increase n by 1.

So you can call concat on a non-array. It doesn't fail. But it doesn't treat non-array array-like things as though they were arrays.

Note Felix's observation that this "only arrays get their entries spread out" is changing in ES6. concat uses a new "is concat spreadable" flag on objects to determine whether it should loop through their entries. I don't think the arguments object will have that flag, though (at least, I don't see anything saying so in §9.4.4), probably to avoid issues with backward-compatibility.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks for the explanation. It seems that I've put a stupid question :P – Dolphin_Wood Apr 04 '15 at 13:21
  • 1
    @DolphinWood: I wouldn't say that. Reading the spec isn't as easy as it might be (sadly, that's getting worse, not better -- the ES6 spec makes the ES5 spec look like a children's book!). – T.J. Crowder Apr 04 '15 at 13:33