Given Array.from
takes an iterable or array-like object as it's first argument, why does it not throw an error when passed an empty object, like this:
let emptyObject = Array.from( {} )
At iterable is defined as an object that implements the iterable protocol or the iterator protocol. An empty object seemingly does neither:
let emptyObject = {}
console.log(emptyObject[Symbol.iterator])
console.log(emptyObject['next'])
console.log(Array.from(emptyObject))
An Array-like object has a length
property and can be indexed (ref). An empty object does not have a length
property.
let emptyObject = {}
console.log(emptyObject['length'])
console.log(Array.from(emptyObject))
How does an empty object qualify?
Array.from()
works with array-like objects. More specifically it only really needs the length
property:
console.log( Array.from({length: 5}) ); //array with 5 slots
This is defined in starting at step 7. of the Array.from algorithm
23.1.2.1 Array.from ( items [ , mapfn [ , thisArg ] ] )
[...]
- Let arrayLike be ! ToObject(items).
- Let len be ? LengthOfArrayLike(arrayLike).
[...]
LengthOfArrayLike
is only this step:
7.3.18 LengthOfArrayLike ( obj )
[...]
Return ℝ(? ToLength(? Get(obj, "length"))).
Which means to retrieve the value of the length
property of an object and defer to ToLength
to convert it to a number. ToLength
is defined as the following:
7.1.20 ToLength ( argument )
[...]
- Let len be ? ToIntegerOrInfinity(argument).
- If len ≤ 0, return +0𝔽.
- Return 𝔽(min(len, 253 - 1)). Therefore a missing
length
meansargument
isundefined
which at step 1. would be converted to zero.