Stage 3 Draft / April 10, 2024

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 SetterThatIgnoresPrototypeProperties ( this, home, p, v )

The abstract operation SetterThatIgnoresPrototypeProperties takes arguments this (an ECMAScript language value), home (an Object), p (a property key), and v (an ECMAScript language value) and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. If this is not an Object, then
    1. Throw a TypeError exception.
  2. If this is home, then
    1. NOTE: Throwing here emulates assignment to a non-writable data property on the home object in strict mode code.
    2. Throw a TypeError exception.
  3. Let desc be ? this.[[GetOwnProperty]](p).
  4. If desc is undefined, then
    1. Perform ? CreateDataPropertyOrThrow(this, p, v).
  5. Else,
    1. Perform ? Set(this, p, v, true).
  6. Return unused.

2.2 Operations on Iterator Objects

2.2.1 GetIteratorDirect ( obj )

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

  1. Let nextMethod be ? Get(obj, "next").
  2. Let iteratorRecord be Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
  3. Return iteratorRecord.

2.2.2 GetIteratorFlattenable ( obj, stringHandling )

The abstract operation GetIteratorFlattenable takes arguments obj (an ECMAScript language value) and stringHandling (iterate-strings or reject-strings) 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, then
    1. If stringHandling is reject-strings or obj is not a String, throw a TypeError exception.
  2. Let method be ? GetMethod(obj, @@iterator).
  3. If method is undefined, then
    1. Let iterator be obj.
  4. Else,
    1. Let iterator be ? Call(method, obj).
  5. If iterator is not an Object, throw a TypeError exception.
  6. Return ? GetIteratorDirect(iterator).

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. Let iteratorRecord be ? GetIteratorFlattenable(O, iterate-strings).
  2. Let hasInstance be ? OrdinaryHasInstance(%Iterator%, iteratorRecord.[[Iterator]]).
  3. If hasInstance is true, then
    1. Return iteratorRecord.[[Iterator]].
  4. Let wrapper be OrdinaryObjectCreate(%WrapForValidIteratorPrototype%, « [[Iterated]] »).
  5. Set wrapper.[[Iterated]] to iteratorRecord.
  6. 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 O be this value.
  2. Perform ? RequireInternalSlot(O, [[UnderlyingIterator]]).
  3. Assert: O has a [[GeneratorState]] slot.
  4. If O.[[GeneratorState]] is suspended-start, then
    1. Set O.[[GeneratorState]] to completed.
    2. NOTE: Once a generator enters the completed state it never leaves it and its associated execution context is never resumed. Any execution state associated with O can be discarded at this point.
    3. Perform ? IteratorClose(O.[[UnderlyingIterator]], NormalCompletion(unused)).
    4. Return CreateIterResultObject(undefined, true).
  5. Let C be Completion { [[Type]]: return, [[Value]]: undefined, [[Target]]: empty }.
  6. Return ? GeneratorResumeAbrupt(O, 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

Iterator.prototype.constructor is an accessor property with attributes { [[Enumerable]]: false, [[Configurable]]: true }. The [[Get]] and [[Set]] attributes are defined as follows:

3.1.3.1.1 get Iterator.prototype.constructor

The value of the [[Get]] attribute is a built-in function that requires no arguments. It performs the following steps when called:

  1. Return %Iterator%.

3.1.3.1.2 set Iterator.prototype.constructor

The value of the [[Set]] attribute is a built-in function that takes an argument v. It performs the following steps when called:

  1. Perform ? SetterThatIgnoresPrototypeProperties(this value, %Iterator.prototype%, "constructor", v).
  2. Return undefined.
Note

Unlike the "constructor" property on most built-in prototypes, for web-compatibility reasons this property must be an accessor.

3.1.3.2 Iterator.prototype.map ( mapper )

This method performs the following steps when called:

  1. Let O be the this value.
  2. If O is not an Object, throw a TypeError exception.
  3. If IsCallable(mapper) is false, throw a TypeError exception.
  4. Let iterated be ? GetIteratorDirect(O).
  5. 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 value be ? IteratorStepValue(iterated).
      2. If value is done, return undefined.
      3. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
      4. IfAbruptCloseIterator(mapped, iterated).
      5. Let completion be Completion(Yield(mapped)).
      6. IfAbruptCloseIterator(completion, iterated).
      7. Set counter to counter + 1.
  6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
  7. Set result.[[UnderlyingIterator]] to iterated.
  8. Return result.

3.1.3.3 Iterator.prototype.filter ( predicate )

This method performs the following steps when called:

  1. Let O be the this value.
  2. If O is not an Object, throw a TypeError exception.
  3. If IsCallable(predicate) is false, throw a TypeError exception.
  4. Let iterated be ? GetIteratorDirect(O).
  5. 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 value be ? IteratorStepValue(iterated).
      2. If value is done, return undefined.
      3. Let selected be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
      4. IfAbruptCloseIterator(selected, iterated).
      5. If ToBoolean(selected) is true, then
        1. Let completion be Completion(Yield(value)).
        2. IfAbruptCloseIterator(completion, iterated).
      6. Set counter to counter + 1.
  6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
  7. Set result.[[UnderlyingIterator]] to iterated.
  8. Return result.

3.1.3.4 Iterator.prototype.take ( limit )

This method performs the following steps when called:

  1. Let O be the this value.
  2. If O is not an Object, throw a TypeError exception.
  3. Let numLimit be ? ToNumber(limit).
  4. If numLimit is NaN, throw a RangeError exception.
  5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
  6. If integerLimit < 0, throw a RangeError exception.
  7. Let iterated be ? GetIteratorDirect(O).
  8. 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 value be ? IteratorStepValue(iterated).
      4. If value is done, return undefined.
      5. Let completion be Completion(Yield(value)).
      6. IfAbruptCloseIterator(completion, iterated).
  9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
  10. Set result.[[UnderlyingIterator]] to iterated.
  11. Return result.

3.1.3.5 Iterator.prototype.drop ( limit )

This method performs the following steps when called:

  1. Let O be the this value.
  2. If O is not an Object, throw a TypeError exception.
  3. Let numLimit be ? ToNumber(limit).
  4. If numLimit is NaN, throw a RangeError exception.
  5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
  6. If integerLimit < 0, throw a RangeError exception.
  7. Let iterated be ? GetIteratorDirect(O).
  8. 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 value be ? IteratorStepValue(iterated).
      2. If value is done, return undefined.
      3. Let completion be Completion(Yield(value)).
      4. IfAbruptCloseIterator(completion, iterated).
  9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
  10. Set result.[[UnderlyingIterator]] to iterated.
  11. Return result.

3.1.3.6 Iterator.prototype.flatMap ( mapper )

This method performs the following steps when called:

  1. Let O be the this value.
  2. If O is not an Object, throw a TypeError exception.
  3. If IsCallable(mapper) is false, throw a TypeError exception.
  4. Let iterated be ? GetIteratorDirect(O).
  5. 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 value be ? IteratorStepValue(iterated).
      2. If value is done, return undefined.
      3. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
      4. IfAbruptCloseIterator(mapped, iterated).
      5. Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-strings)).
      6. IfAbruptCloseIterator(innerIterator, iterated).
      7. Let innerAlive be true.
      8. Repeat, while innerAlive is true,
        1. Let innerValue be Completion(IteratorStepValue(innerIterator)).
        2. IfAbruptCloseIterator(innerValue, iterated).
        3. If innerValue is done, then
          1. Set innerAlive to false.
        4. Else,
          1. Let completion be Completion(Yield(innerValue)).
          2. If completion is an abrupt completion, then
            1. Let backupCompletion be Completion(IteratorClose(innerIterator, completion)).
            2. IfAbruptCloseIterator(backupCompletion, iterated).
            3. Return ? IteratorClose(completion, iterated).
      9. Set counter to counter + 1.
  6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
  7. Set result.[[UnderlyingIterator]] to iterated.
  8. Return result.

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

This method performs the following steps when called:

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

3.1.3.8 Iterator.prototype.toArray ( )

This method performs the following steps when called:

  1. Let O be the this value.
  2. If O is not an Object, throw a TypeError exception.
  3. Let iterated be ? GetIteratorDirect(O).
  4. Let items be a new empty List.
  5. Repeat,
    1. Let value be ? IteratorStepValue(iterated).
    2. If value is done, return CreateArrayFromList(items).
    3. Append value to items.

3.1.3.9 Iterator.prototype.forEach ( fn )

This method performs the following steps when called:

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

3.1.3.10 Iterator.prototype.some ( predicate )

This method performs the following steps when called:

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

3.1.3.11 Iterator.prototype.every ( predicate )

This method performs the following steps when called:

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

3.1.3.12 Iterator.prototype.find ( predicate )

This method performs the following steps when called:

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

3.1.3.13 Iterator.prototype [ @@toStringTag ]

Iterator.prototype[@@toStringTag] is an accessor property with attributes { [[Enumerable]]: false, [[Configurable]]: true }. The [[Get]] and [[Set]] attributes are defined as follows:

3.1.3.13.1 get Iterator.prototype [ @@toStringTag ]

The value of the [[Get]] attribute is a built-in function that requires no arguments. It performs the following steps when called:

  1. Return "Iterator".

3.1.3.13.2 set Iterator.prototype [ @@toStringTag ]

The value of the [[Set]] attribute is a built-in function that takes an argument v. It performs the following steps when called:

  1. Perform ? SetterThatIgnoresPrototypeProperties(this value, %Iterator.prototype%, %Symbol.toStringTag%, v).
  2. Return undefined.
Note

Unlike the @@toStringTag property on most built-in prototypes, for web-compatibility reasons this property must be an accessor.

4 Updated Abstract Operations

4.1 CreateIteratorFromClosure ( closure, generatorBrand, generatorPrototype [ , extraSlots ] )

The abstract operation CreateIteratorFromClosure takes arguments closure (an Abstract Closure with no parameters), generatorBrand (a String or empty), and generatorPrototype (an Object) and optional argument extraSlots (a List of names of internal slots) and returns a Generator. It performs the following steps when called:

  1. NOTE: closure can contain uses of the Yield operation to yield an IteratorResult object.
  2. If extraSlots is not present, set extraSlots to a new empty List.
  3. Let internalSlotsList be the list-concatenation of extraSlots and « [[GeneratorState]], [[GeneratorContext]], [[GeneratorBrand]] ».
  4. Let generator be OrdinaryObjectCreate(generatorPrototype, internalSlotsList).
  5. Set generator.[[GeneratorBrand]] to generatorBrand.
  6. Set generator.[[GeneratorState]] to undefined.
  7. Let callerContext be the running execution context.
  8. Let calleeContext be a new execution context.
  9. Set the Function of calleeContext to null.
  10. Set the Realm of calleeContext to the current Realm Record.
  11. Set the ScriptOrModule of calleeContext to callerContext's ScriptOrModule.
  12. If callerContext is not already suspended, suspend callerContext.
  13. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
  14. Perform GeneratorStart(generator, closure).
  15. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
  16. Return generator.