Peter Weightman
Back

Dangers of JS Spread Operator

The spread operator can be used to (among other things) expand arrays in places where elements are expected.

Example:

const data = [0, 1, 2];
const additionalData = [3, 4, 5];

data.push(...additionalData);

That's handy but if you aren't careful you can run into: RangeError: Maximum call stack size exceeded at Array.push

This happens if the array you're spreading is too large.

Let's imagine this scenario:

const allData = [];

for (const month of months) {
	const dataForMonth = await fetchDataForMonth(month);
	allData.push(...dataForMonth);
}

If we don't know how many elements dataForMonth might have we could hit this limit. In this case, instead of arr.push(...data) we can do arr.push.apply(arr, data).

To test, I ran this script on the node repl in my terminal:

let arrOne = [];
const arrTwo = [];
while (true) {
	arrTwo.push(null);
	console.log('items: ', arrTwo.length);
	arrOne.push(...arrTwo);
	arrOne = [];
}

and the last log before the error is: items: 125639


Interestingly, I tried a couple of variations and got different results, suggesting this isn't a general limitation of the spread operator but depends in the context it's being used:

  1. First Variation:
const arrOne = [];
const arrTwo = [];
while (true) {
	arrTwo.push(null);
	console.log('items: ', arrTwo.length);
	const combined = [...arrOne, ...arrTwo];
}

I kept this running for a while but eventually stopped it before it errored as it had got my laptop fans running loudly. I presume it would have errored eventually but can't say for certain. It got to items: 225035 before I stopped the script with no error.

  1. Second Variation:
const arr = [];
const func = () => null;
while (true) {
	arr.push(null);
	console.log('item count: ', arr.length);
	func(...arr);
}

This hit the RangeError with the item count: 120587 as the final line of logging.