Overview
a.push(...b)
- limited, fast, modern syntax
a.push.apply(a, b)
- limited, fast
a = a.concat(b)
unlimited, slow if a
is large
for (let i in b) { a.push(b[i]); }
- unlimited, slow if b
is large
Each snippet modifies a
to be extended with b
.
The "limited" snippets pass each array element as an argument, and the maximum number of arguments you can pass to a function is limited. From that link, it seems that a.push(...b)
is reliable until there are about 32k elements in b
(the size of a
does not matter).
Relevant MDN documentation: spread syntax, .apply(), .concat(), .push()
Speed considerations
Every method is fast if both a
and b
are small, so in most web applications you'll want to use push(...b)
and be done with it.
If you're handling more than a few thousand elements, what you want to do depends on the situation:
- you're adding a few elements to a large array
→ push(...b)
is very fast
- you're adding many elements to a large array
→ concat
is slightly faster than a loop
- you're adding many elements to a small array
→ concat
is much faster than a loop
This surprised me: I figured a=a.concat(b)
would be able to do a nice memcpy of b
onto a
without bothering to do individual extend operations as a.push(...b)
would have to do, thus always being the fastest. Instead, a.push(...b)
is much, much faster especially when a
is large.
The speed of different methods was measured in Firefox 88 on Linux using:
a = [];
for (let i = 0; i < Asize; i++){
a.push(i);
}
b = [];
for (let i = 0; i < Bsize; i++){
b.push({something: i});
}
t=performance.now();
console.log(performance.now() - t);
Parameters and results:
ms | Asize | Bsize | code
----+-------+-------+------------------------------
~0 | any | any | a.push(...b)
~0 | any | any | a.push.apply(a, b)
480 | 10M | 50 | a = a.concat(b)
0 | 10M | 50 | for (let i in b) a.push(b[i])
506 | 10M | 500k | a = a.concat(b)
882 | 10M | 500k | for (let i in b) a.push(b[i])
11 | 10 | 500k | a = a.concat(b)
851 | 10 | 500k | for (let i in b) a.push(b[i])
Note that a Bsize
of 500 000 is the largest value accepted by all methods on my system, that's why it is smaller than Asize
.
All tests were run multiple times to see if the results are outliers or representative. The fast methods are almost immeasurable in just one run using performance.now()
, of course, but since the slow methods are so obvious and the two fast methods both work on the same principle, we needn't bother repeating it a bunch of times to split hairs.
The concat
method is always slow if either array is large, but the loop is only slow if it has to do a lot of function calls and doesn't care how large a
is. A loop is thus similar to push(...b)
or push.apply
for small b
s but without breaking if it does get large; however, when you approach the limit, concat
is a bit faster again.
a.push(...b)
. It's similar in concept to the top answer, but updated for ES6. - tscizzle