by @zhangbao(zhangbao) #0104

An iterable can be thought of as “an Array in the broad sense” — that is, not necessarily an Array(array.isarray (iterable) returns false), but can be for… The of loop traverses.

An overview of

  • An iterable doesn’t have to be an array; an array must be an iterable.
  • Each iterable must contain one[Symbol.iterator]The method attributes
  • Strings are also iterable

Transform common objects

Let’s take an example. Here’s an object:

let range = {
  from: 1.to: 5
};

// We want to use for.. Of traverses the range to get the natural numbers from 1 (from) to 5 (to)
// for(let num of range) {sol.log(num)
Copy the code

Range is an iterable object. Range is an iterable object. Also use for.. 1 -> 2 -> 3 -> 4 -> 5 That’s right. It’s bullshit now, because we didn’t do anything. It’s bullshit, right?

In order to make range an iterable, we need to understand the system preset variable symbol. iterator.

Symbol.iterator

So let’s look at what the description of this property looks like.

Object.getOwnPropertyDescriptor(Symbol.'iterator')
/ / {
// value: Symbol(Symbol.iterator),
// writable: false,
// enumerable: false,
// configurable: false
// }
Copy the code

The result shows that we cannot modify this property.

Iterator: [Symbol. Iterator] : [Symbol. Iterator] : [Symbol. Iterator] : [Symbol. Iterator: [Symbol.

let range = {
  from: 1.to: 5
}

// 1. for.. The of loop first calls the [symbol.iterator] property on the object -- range[symbol.iterator](),
// Attribute range[symbol.iterator] is called "iterator generator" or "iterator generator"
range[Symbol.iterator] = function() {
	
  // range[symbol.iterator]() returns an object containing the next method,
  // This object is called "iteration object"
  // 2. Of is completely dealing with the iterator
  return {
    current: this.from,
    last: this.to,
    
    // 3. The next method is called once through the "of" loop
    next() {
      // 4. From the next method, we can get the value of the current traversal and the done flag.
      if (this.current <= this.last) {
        return { done: false.value: this.current++ }
      } else {
        return { done: true }
      }
    }
  }
}
Copy the code

for… The essence of the OF loop traversal is:

  1. for.. ofThe loop first invokes method properties on the object[Symbol.iterator]range[Symbol.iterator](), and you get a containnextMethod object.
  • This includesnextThe object of the method is calledIterator objects
  • attributerange[Symbol.iterator]Referred to asIterator generatororIterating over objects generates functions
  1. Next,for.. ofI’m completely dealing with this iterator,
  2. Every timefor.. ofOnce through the loop, it’s called oncenextMethod,
  3. fromnextThe object returned by the{ done: ... , value: ... }), we can get the value of the current traversal (value) and whether the traversal is over (done).

After the above statement, we can also define an iterable as an object that produces an “iterable”. 支那

Iterate over the transformed object

Now iterate over the modified Range object.

let range = {
  from: 1.to: 5
}
range[Symbol.iterator] = function() {... }for (let num of range) {
  console.log(num) // 1, then 2, 3, 4, 5
}
Copy the code

Very cool, now you can iterate through the 5 numbers 1 -> 2 -> 3 -> 4 -> 5 in one go.

Manually traverse the iterable

For fun, let’s imitate for… Of executes the flow inside the loop. Write the logic for iterating through the iterable by hand.

The while loop is used here:

// The following is equivalent to
// for (let num of range) { console.log(num) };

let iterator = range[Symbol.iterator]();

while (true) {
  let result = iterator.next();
  // The done flag (true) terminates the loop and completes the loop
  if (result.done) break;
  // Otherwise, print the current traversal value
  console.log(result.value);
}
Copy the code
  1. First, call manuallyrange[Symbol.iterator]Method, get the iteration object
  2. inwhileInside the loop:
  3. If the flag ends (donetrue), terminates the loop and completes the traversal
  4. Otherwise, the value of the current loop is printed

Built-in iterables

We said that an iterable is not necessarily an array, but an array must be an iterable. We know from experience that arrays can be used with for… Of is iterated.

An array of

Traversing the symbols is for… The of loop iterated successfully. This is to be expected, but let’s see if the array object has a property called symbol. iterator 🕵️♂️

Sure enough!

string

Strings are also iterable. Here’s the evidence:

Look again for the symbol. iterator attribute.

The Map and Set

Maps and sets can also be used for… Of traversal. Without further examples, I will show the symbol.iterator properties that each of them deploys.

From the screenshot above, we can summarize a few things:

  1. The default iterator generator function for a Map object ismap.entries()And the
  2. The default iterator generator function for Set ismap.values()

For more information about traversal of Map and Set objects, see Traversal of Map and Set.

(after)