First, the expression to the right of the ...
is evaluated. That is, Array(5).keys() + 1
gets evaluated, and the result of that evaluation is then spread. Grouping the expression may make things a little clearer:
[...(Array(5).keys() + 1)]
So, above, we start with calculating the result of Array(5).keys() + 1
. The +
operator works between primitive operands. When you do Array(5).keys()
you get an iterator back which is not classified as a primitive. So, JS will try and convert it to a primitive. When JS tries to convert the iterator into a primitive in this context it tries to:
- Invoke the iterator's
Symbol.toPrimitive
method, since this doesn't exist, it moves onto trying the next step
- Invoke the
.valueOf()
method of the iterator. This succeeds, but it returns the iterator back, which is not a primitive, so we go to the next step
- Invoke the
.toString()
method. This results in a non-object type (ie: a string), and so this is successful.
When the iterator's .toString()
method is called it gets evaluated to "[object Array Iterator]"
. As this then gets added with the number 1
, we concatenate the string with the number (rather than add), giving:
[..."[object Array Iterator]1"]
Since strings are iterable, the spread syntax will use the string's iterator to loop through the code points in the string, resulting in every character of the string becoming its own element:
["[", "o", "b", "j", "e", "c", "t", " ", "A", "r", "r", "a", "y", " ", "I", "t", "e", "r", "a", "t", "o", "r", "]", "1"]
In order to add one to each item in your iterator, you can use Array.from()
which can take an iterator, and applies a mapping function to each element:
const res = Array.from(Array(5).keys(), i => i+1);
console.log(res);