Ben Aston
Ben Aston

Reputation: 55729

Why do map, foreach and reduce not use the iterator function on Symbol.iterator?

Why do map, foreach, and reduce, not use the iterator function on Symbol.iterator?

class MyArray extends Array {
    *[Symbol.iterator]() {
        for(let x = 0; x < this.length; x++) { yield this[x]*2 }
    }
}

const log = console.log
const arr = new MyArray(1,2,3)
console.log([...arr]) // [2,4,6]
log(arr.map((i) => i)) // [1,2,3]

And:

const arr = [1,2,3]
Object.defineProperty(Object.getPrototypeOf(arr), Symbol.iterator, { 
    value: function*() {
        for(let x = 0; x < this.length; x++) { yield this[x]*2 }
    }
})

const log = console.log
log([...arr]) // [2,4,6]
log(arr.map((i) => i)) // [1,2,3]

Upvotes: 6

Views: 349

Answers (1)

Pointy
Pointy

Reputation: 413682

The "old" Array methods are explicitly specified such that iteration is in terms of a simple sequence of numeric indexes. See for example the ES2016 spec.

You can use Array.from(arr) to make your iterator work, and then call .forEach() on the result.

Note that for some of the iteration methods, the specified behavior is to only invoke the callback for indexes that actually have an assigned value. Because using the iterator would mean iterating through all the values, that would be problematic. All the iterator function can do for unassigned values is return undefined, but then it'd be ambiguous; does it mean the slot in the container has never been assigned a value, or does it mean it was explicitly assigned undefined?

Upvotes: 3

Related Questions