Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between Array.from() and Array.apply()?

I got "Maximum call stack size exceeded." error when using Array.apply() to convert a large Uint8Array to an Array.

I found that apply() passes my parameter array as arguments in Array's constructor and function's arguments are stored in stack. Therefore, if I pass a large array to apply(), it'll exceed the stack.

After some searching, I changed to use Array.from() and it solved my issue.

I read the algorithm in ECMAScript but I can't understand it. So, could someone tell me the difference between apply() and from()?

like image 458
IFZR Avatar asked Dec 11 '25 20:12

IFZR


1 Answers

Array.apply calls Function.prototype.apply with a calling context (a this value) of Array. If the second parameter is an array-like object, it will call the Array constructor with all of the elements of that array-like object as arguments. Eg:

Array.apply(null, [1, 2, 3, 4])

results in, and is equivalent to

Array(1, 2, 3, 4)

But argument lists have a size limit. It depends on the engine, but it looks like you probably shouldn't try to pass more than 10,000 arguments or so.

In contrast, Array.from invokes the iterator of the array-like object. If the iterator doesn't exist, but the object has a length property, it will iterate from 0 up to the value of the length - 1 and create an array from those values. Here, since a Uint8Array has an iterator, that iterator is what gets invoked when you use Array.from.

Iterators don't have the same sort of size limit that argument lists have (unless they're spread into an argument list, or something similar). The iterator's .next method is called, returning a value to put into the array, until the iterator is exhausted. It's pretty similar to the following:

const arr = [0, 1, 2];

// Create a new array by iterating through arr's iterator
// just like Array.from is doing:
const newArr = [];
const iterator = arr[Symbol.iterator]();
let iterObj = iterator.next();
while (!iterObj.done) {
  newArr.push(iterObj.value);
  iterObj = iterator.next(); 
}
console.log(newArr);

There are no limits on how long the iterator may be, either in the above code, or in Array.from.

So, if the iterable or array-like object you have is very large, constructing an array from it with Array.apply (or by spreading into the Array constructor) may throw an error, whereas using Array.from will not.

like image 57
CertainPerformance Avatar answered Dec 14 '25 09:12

CertainPerformance



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!