Stage 3 Draft / February 6, 2023

Iterator Helpers

Contributing to this Proposal

This proposal is developed on GitHub with the help of the ECMAScript community. There are a number of ways to contribute to the development of this specification:

1 Well-Known Intrinsic Objects

Table 1: Well-Known Intrinsic Objects
Intrinsic Name Global Name ECMAScript Language Association
%Iterator% Iterator The Iterator constructor (3.1.1.1)
%IteratorPrototype% Iterator.prototype An object that all standard built-in iterator objects indirectly inherit from

The initial value of the "prototype" data property of %Iterator%; i.e., %Iterator.prototype%

2 Abstract Operations

2.1 Operations on Iterator Objects

2.1.1 GetIteratorDirect ( obj )

The abstract operation GetIteratorDirect takes argument obj (an ECMAScript language value) and returns either a normal completion containing an Iterator Record or a throw completion. It performs the following steps when called:

  1. If obj is not an Object, throw a TypeError exception.
  2. Let nextMethod be ? Get(obj, "next").
  3. If IsCallable(nextMethod) is false, throw a TypeError exception.
  4. Let iteratorRecord be Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
  5. Return iteratorRecord.

2.1.2 GetIteratorFlattenable ( obj, hint )

The abstract operation GetIteratorFlattenable takes arguments obj (an ECMAScript language value) and hint (sync or async) and returns either a normal completion containing an Iterator Record or a throw completion. It performs the following steps when called:

  1. If obj is not an Object, throw a TypeError exception.
  2. Let alreadyAsync be false.
  3. Let method be undefined.
  4. If hint is async, then
    1. Set method to ? Get(obj, @@asyncIterator).
    2. Set alreadyAsync to true.
  5. If IsCallable(method) is false, then
    1. Set method to ? Get(obj, @@iterator).
    2. Set alreadyAsync to false.
  6. If IsCallable(method) is false, then
    1. Let iterator be obj.
    2. Set alreadyAsync to true.
  7. Else,
    1. Let iterator be ? Call(method, obj).
  8. If iterator is not an Object, throw a TypeError exception.
  9. Let nextMethod be ? Get(iterator, "next").
  10. If IsCallable(nextMethod) is false, throw a TypeError exception.
  11. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
  12. If hint is async and alreadyAsync is false, then
    1. Return CreateAsyncFromSyncIterator(iteratorRecord).
  13. Return iteratorRecord.

3 Control Abstraction Objects

3.1 Iteration

3.1.1 Iterator Objects

3.1.1.1 The Iterator Constructor

The Iterator constructor:

  • is %Iterator%.
  • is the initial value of the Iterator property of the global object.
  • is designed to be subclassable. It may be used as the value of an extends clause of a class definition.

3.1.1.1.1 Iterator ( )

When the Iterator function is called, the following steps are taken:

  1. If NewTarget is undefined or the active function object, throw a TypeError exception.
  2. Return ? OrdinaryCreateFromConstructor(NewTarget, "%Iterator.prototype%").

3.1.1.2 Properties of the Iterator Constructor

3.1.1.2.1 Iterator.prototype

The initial value of Iterator.prototype is %Iterator.prototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

3.1.1.2.2 Iterator.from ( O )

  1. If O is a String, set O to ! ToObject(O).
  2. Let iteratorRecord be ? GetIteratorFlattenable(O, sync).
  3. Let hasInstance be ? OrdinaryHasInstance(%Iterator%, iteratorRecord.[[Iterator]]).
  4. If hasInstance is true, then
    1. Return iteratorRecord.[[Iterator]].
  5. Let wrapper be OrdinaryObjectCreate(%WrapForValidIteratorPrototype%, « [[Iterated]] »).
  6. Set wrapper.[[Iterated]] to iteratorRecord.
  7. Return wrapper.

3.1.1.2.2.1 The %WrapForValidIteratorPrototype% Object

The %WrapForValidIteratorPrototype% object:

3.1.1.2.2.1.1 %WrapForValidIteratorPrototype%.next ( )

  1. Let O be this value.
  2. Perform ? RequireInternalSlot(O, [[Iterated]]).
  3. Let iteratorRecord be O.[[Iterated]].
  4. Return ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).

3.1.1.2.2.1.2 %WrapForValidIteratorPrototype%.return ( )

  1. Let O be this value.
  2. Perform ? RequireInternalSlot(O, [[Iterated]]).
  3. Let iterator be O.[[Iterated]].[[Iterator]].
  4. Assert: iterator is an Object.
  5. Let returnMethod be ? GetMethod(iterator, "return").
  6. If returnMethod is undefined, then
    1. Return CreateIterResultObject(undefined, true).
  7. Return ? Call(returnMethod, iterator).

3.1.2 Iterator Helper Objects

An Iterator Helper object is an ordinary object that represents a lazy transformation of some specific source iterator object. There is not a named constructor for Iterator Helper objects. Instead, Iterator Helper objects are created by calling certain methods of Iterator instance objects.

3.1.2.1 The %IteratorHelperPrototype% Object

The %IteratorHelperPrototype% object:

3.1.2.1.1 %IteratorHelperPrototype%.next ( )

  1. Return ? GeneratorResume(this value, undefined, "Iterator Helper").

3.1.2.1.2 %IteratorHelperPrototype%.return ( )

  1. Let C be Completion { [[Type]]: return, [[Value]]: undefined, [[Target]]: empty }.
  2. Return ? GeneratorResumeAbrupt(this value, C, "Iterator Helper").

3.1.2.1.3 %IteratorHelperPrototype% [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Iterator Helper".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

3.1.3 Iterator.prototype

The Iterator prototype object:

3.1.3.1 Iterator.prototype.constructor

The initial value of %Iterator.prototype%.constructor is %Iterator%.

3.1.3.2 Iterator.prototype.map ( mapper )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(mapper) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? IteratorStep(iterated).
      2. If next is false, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseIterator(mapped, iterated).
      6. Let completion be Completion(Yield(mapped)).
      7. IfAbruptCloseIterator(completion, iterated).
      8. Set counter to counter + 1.
  4. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.3.3 Iterator.prototype.filter ( predicate )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(predicate) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and predicate and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? IteratorStep(iterated).
      2. If next is false, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let selected be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseIterator(selected, iterated).
      6. If ToBoolean(selected) is true, then
        1. Let completion be Completion(Yield(value)).
        2. IfAbruptCloseIterator(completion, iterated).
      7. Set counter to counter + 1.
  4. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.3.4 Iterator.prototype.take ( limit )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let numLimit be ? ToNumber(limit).
  3. If numLimit is NaN, throw a RangeError exception.
  4. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
  5. If integerLimit < 0, throw a RangeError exception.
  6. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
    1. Let remaining be integerLimit.
    2. Repeat,
      1. If remaining is 0, then
        1. Return ? IteratorClose(iterated, NormalCompletion(undefined)).
      2. If remaining is not +∞, then
        1. Set remaining to remaining - 1.
      3. Let next be ? IteratorStep(iterated).
      4. If next is false, return undefined.
      5. Let completion be Completion(Yield(? IteratorValue(next))).
      6. IfAbruptCloseIterator(completion, iterated).
  7. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.3.5 Iterator.prototype.drop ( limit )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let numLimit be ? ToNumber(limit).
  3. If numLimit is NaN, throw a RangeError exception.
  4. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
  5. If integerLimit < 0, throw a RangeError exception.
  6. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
    1. Let remaining be integerLimit.
    2. Repeat, while remaining > 0,
      1. If remaining is not +∞, then
        1. Set remaining to remaining - 1.
      2. Let next be ? IteratorStep(iterated).
      3. If next is false, return undefined.
    3. Repeat,
      1. Let next be ? IteratorStep(iterated).
      2. If next is false, return undefined.
      3. Let completion be Completion(Yield(? IteratorValue(next))).
      4. IfAbruptCloseIterator(completion, iterated).
  7. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.3.6 Iterator.prototype.flatMap ( mapper )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(mapper) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? IteratorStep(iterated).
      2. If next is false, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseIterator(mapped, iterated).
      6. Let innerIterator be Completion(GetIteratorFlattenable(mapped, sync)).
      7. IfAbruptCloseIterator(innerIterator, iterated).
      8. Let innerAlive be true.
      9. Repeat, while innerAlive is true,
        1. Let innerNext be Completion(IteratorStep(innerIterator)).
        2. IfAbruptCloseIterator(innerNext, iterated).
        3. If innerNext is false, then
          1. Set innerAlive to false.
        4. Else,
          1. Let innerValue be Completion(IteratorValue(innerNext)).
          2. IfAbruptCloseIterator(innerValue, iterated).
          3. Let completion be Completion(Yield(innerValue)).
          4. If completion is an abrupt completion, then
            1. Let backupCompletion be Completion(IteratorClose(innerIterator, completion)).
            2. IfAbruptCloseIterator(backupCompletion, iterated).
            3. Return ? IteratorClose(completion, iterated).
      10. Set counter to counter + 1.
  4. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.3.7 Iterator.prototype.reduce ( reducer [ , initialValue ] )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(reducer) is false, throw a TypeError exception.
  3. If initialValue is not present, then
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, throw a TypeError exception.
    3. Let accumulator be ? IteratorValue(next).
    4. Let counter be 1.
  4. Else,
    1. Let accumulator be initialValue.
    2. Let counter be 0.
  5. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return accumulator.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(reducer, undefined, « accumulator, value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. Set accumulator to result.[[Value]].
    7. Set counter to counter + 1.

3.1.3.8 Iterator.prototype.toArray ( )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let items be a new empty List.
  3. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return CreateArrayFromList(items).
    3. Let value be ? IteratorValue(next).
    4. Append value to items.

3.1.3.9 Iterator.prototype.forEach ( fn )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return undefined.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. Set counter to counter + 1.

3.1.3.10 Iterator.prototype.some ( predicate )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(predicate) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return false.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. If ToBoolean(result) is true, return ? IteratorClose(iterated, NormalCompletion(true)).
    7. Set counter to counter + 1.

3.1.3.11 Iterator.prototype.every ( predicate )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(predicate) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return true.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)).
    7. Set counter to counter + 1.

3.1.3.12 Iterator.prototype.find ( predicate )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(predicate) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return undefined.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. If ToBoolean(result) is true, return ? IteratorClose(iterated, NormalCompletion(value)).
    7. Set counter to counter + 1.

3.1.3.13 Iterator.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Iterator".

Note

Unlike the @@toStringTag on most built-in classes, for web-compatibility reasons this property must be writable.