skip to Main Content

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?

3

Answers


  1. Seems it create just an empty array for values not qualified as iterable or array like except null and undefined since no iterator can be read from them (you can read an iterator from non-nullish values, it just will be undefined). So with no iterator fetched just an empty array is created.

    console.log(Array.from(1));
    console.log(Array.from(false));
    console.log(Array.from(null));
    Login or Signup to reply.
  2. When passing a non-empty argument, it seems it checks [Symbol.iterator] first, if it doesn’t exist, it then checks length property. If neither of them exist, fallback to an empty array.

    // Neither `length` or `[Symbol.iterator]` exist, empty array
    const arr1 = Array.from({});
    console.log('arr1', arr1);
    
    const arr2 = Array.from({ length: 2 });
    console.log('arr2', arr2);
    
    const arr3 = Array.from({ *[Symbol.iterator]() { yield* [1, 2, 3] } });
    console.log('arr3', arr3);
    
    // Both `length` and `[Symbol.iterator]` exist, using `[Symbol.iterator]`
    const arr4 = Array.from({ length: 2, *[Symbol.iterator]() { yield* [1, 2, 3] } });
    console.log('arr4', arr4);
    Login or Signup to reply.
  3. 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 ] ] )

    […]

    1. Let arrayLike be ! ToObject(items).
    2. Let len be ? LengthOfArrayLike(*arrayLike*).

    […]

    The LengthOfArrayLike itself defers to ToLength which is defined as the following:

    7.1.20 ToLength ( argument )

    […]

    1. Let len be ? ToIntegerOrInfinity(argument).
    2. If len ≤ 0, return +0𝔽.
    3. Return 𝔽(min(len, 253 – 1)).

    A missing length means argument is undefined which at step 1. would be converted to zero.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search