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.