15

The simple code below produces RangeError: Maximum call stack size exceeded

const arr = []
for (let i = 0; i < 135000; i++) {
    arr.push(i)
}
const arr2 = []
// something else here that changes arr2
arr2.push(...arr)

1) Why does this happen? (I am simply adding element to an array, why does it increase stack size ?)

2) How to fix this error ? (My goal is to create a shallow copy of arr into arr2)

TSR
  • 17,242
  • 27
  • 93
  • 197
  • You might want to use [`.concat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) instead. –  May 11 '20 at 22:40
  • 2
    Does this answer your question? [Is there a max number of arguments JavaScript functions can accept?](https://stackoverflow.com/questions/22747068/is-there-a-max-number-of-arguments-javascript-functions-can-accept) – ggorlen May 11 '20 at 22:46

3 Answers3

13

The spread operator there pushes all elements in the original array into the stack, just like .apply:

const arr = [];

for (let i = 0; i < 10; i++) {
  arr.push(i);
}

const arr2 = [];

// Something else here that changes arr2:
arr2.push(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

Array.prototype.push.apply(arr2, arr);

console.log(arr2.join(', '));

So the amount of data you can handle in both cases is limited by the stack size:

const arr = [];

for (let i = 0; i < 135000; i++) {
  arr.push(i);
}

const arr2 = [];

// Something else here that changes arr2:
arr2.push(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

Array.prototype.push.apply(arr2, arr);

console.log(arr.length, arr2.length);

You could do this instead:

const arr = [];

for (let i = 0; i < 135000; i++) {
  arr.push(i);
}

let arr2 = [];

// Something else here that changes arr2:
arr2.push(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

arr2 = [...arr2, ...arr];

console.log(arr.length, arr2.length);
Danziger
  • 19,628
  • 4
  • 53
  • 83
1

When you use spread operator all items of the source array are stored in the stack as arguments list, so having a large number of items (~ > 100K) will cause the this stack size exceed.

The most simple work-around is to manually push all items one by one.

You can have a helper/utility function like this:

function largePush(src, dest){
    const len = src.length
    for(let i = 0; i < len; i++){
        dest.push(src[i])
    }
}

and use it like this:

const arr = []
for (let i = 0; i < 135000; i++) {
    arr.push(i)
}
const arr2 = []
largePush(arr, arr2)
Dahou
  • 522
  • 4
  • 12
-1

//I hope this will help you to make shallow copy of arr into arr2

let arr = []
for (let i = 0; i < 135000; i++) {
    arr.push(i)
}
let arr2 = []
// something else here that changes arr2
arr2=arr

console.log(arr2[0],arr[0]);
//Both 0,0
arr[0]=100

console.log(arr[0],arr2[0])

//Both 100,100
jobayersozib
  • 401
  • 2
  • 7
  • You are not making any copy of the original array, you are just aliasing it in another variable – Dahou Aug 22 '22 at 10:32