1. Iterator Iterator
1.1 What is an iterator?
Definition: An iterator is an object that helps us walk through a data structure.
In javascript, an iterator is also a concrete object that needs to conform to the iterator protocol
-
Iterator Protocol:
-
The iterator protocol defines a standard way to produce a set of values;
-
In JS this standard is a specific next method;
-
-
Next method:
- aNo argument or one argumentReturns a function that should haveObjects with the following two properties:
- Done: False if the iterator can produce the next value in the sequence; True if the sequence has been iterated over;
- Value: Any value returned by the iterator, omitted if done is true;
- aNo argument or one argumentReturns a function that should haveObjects with the following two properties:
Example 1: A simple iterator
const iterator = {
next: function() {
return { done: true.value: 123}}}Copy the code
The iterator above is the simplest iterator, but we know that iterators help us traverse some data structure, so this iterator seems useless.
Example 2: An iterator that iterates through arrays of numbers
const names = ['zhangsan'.'lisi'.'wangwu']
let index = 0
const namesIterator = {
next: function() {
if(index < names.length) {
return { done: false.value: names[index++] }
} else {
return { done: true.value: undefined}}}}Copy the code
Above we create a namesIterator that iterates through the Names array using a call to the next method
console.log(namesIterator.next()) // { done: false, vlaue: 'zhangsan' }
console.log(namesIterator.next()) // { done: false, vlaue: 'lisi' }
console.log(namesIterator.next()) // { done: false, vlaue: 'wangwu' }
console.log(namesIterator.next()) // { done: true, value: undefined }
console.log(namesIterator.next()) // { done: true, value: undefined }
Copy the code
At this point, we should actually have a rudimentary idea of what an iterator is.
- But the above code as a whole looks a bit strange:
- To get an array, you create an Index variable and then an iterator object.
- In fact, we can further encapsulate the above code to make it an iterable;
1.2 What is an iterable?
-
Iterable: An object is an iterable when it implements the Iterable Protocol. Be careful not to be confused with the iterator Protocol.
-
Iterable protocol: The object must implement the @@iterator method. In code we use symbol. iterator to access this property. The function is required to return an iterator
Example 3: Convert Example 2 to an iterable
const iterableObj = {
names: ['zhangsan'.'lisi'.'wangwu'],
[Symbol.iterator]: function() {
let index = 0
return {
next: () = > { // This must be an arrow function pointing to iterableObj to access the names attribute
if(index < this.names.length) {
return { done: false.value: this.names[index++] }
} else {
return { done: true.value: undefined}
}
}
}
}
}
Copy the code
IteratorObj is an iterable because it has a Symbol. Iterator property and returns an iterator
use
const iterator = iterableObj[Symbol.iterator]() // Calling this function returns an iterator
console.log(iterator.next()) // { done: false, vlaue: 'zhangsan' }
console.log(iterator.next()) // { done: false, vlaue: 'lisi' }
console.log(iterator.next()) // { done: false, vlaue: 'wangwu' }
console.log(iterator.next()) // { done: true, value: undefined }
console.log(iterator.next()) // { done: true, value: undefined }
Copy the code
1.3 Application of iterable
1.3.1 Talk about for… of..
-
for… The of statement can be thought of as a syntactic sugar that loops through the next method of the iterable’s custom iterator, returning value when done is false, and stopping when done is true.
-
for… The IN statement iterates through the enumerable properties of an object other than Symbol
for… of.. Iterable objects must be iterable. In and for.. of… Get mixed up and write code like this
Example 4
const obj = {
name: 'zhangsan'.age: 20
}
// Print name age
for(const key in obj) {
console.log(key)
}
TypeError: obj is not iterable* because obj is not iterable
for(const key of obj) {
console.log({key})
}
// Output zhangsan lisi wangwu because iteratorObj is iterable
for(const key of iteratorObj) {
console.log({key})
}
Copy the code
Example 5: ArR is an Array object that already implements the symbol. iterator method inside, so you can use for… Of traversal
const arr = ['zhangsan'.'lisi'.'wangwu']
const iterator = arr[Symbol.iterator]()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
Copy the code
Javascript built-in create iterable: Array, Map, Set, String, TypedArray, arguments
1.3.2 Deconstruction operation
- The essence of destructuring an array is to use iterators
const [name, age] = ['zhangsan'.20]
Copy the code
- Deconstruction of objects is a new feature in ES9: instead of iterators
const { name } = obj
Copy the code
2. Generator
2.1 What is a generator?
Definition: Generators are a new function control and usage scheme in ES6 that gives us more flexibility over when functions are executed, paused, and so on.
Generators are combined with functions, and generally we do not speak of generators directly, but of generator functions, because generators are generated by generator functions
Generators are special iterators
2.2 What are generator functions?
- Generator functions need a * after function
- Generator functions use yield to control the flow of code execution
- The generator function returns a generator
Example 6: A simple generator function foo that returns a generator
function * foo() {
console.log("step 1")
yield
console.log("step 2")
yield
console.log("step 3")}const generator = foo() // Returns a generator function that is not executed internally
Copy the code
2.3 Execution of generator functions
- You can see that function foo is executed above. The body of the function is not executed at all. It just returns a generator object
- So how do I get it to do the function stuff, just call the next method
- Generators are special iterators whose next returns a value
- Yield can be used to return the result
Example 7: Execution of a generator function
function * foo() {
yield 'yield1'
yield 'yield2'
}
const generator = foo() // Returns a generator function that is not executed internally
// Execute the first yield and pause
console.log(generator.next()) // { value: 'yeild 1', done: false }
// Execute the second yield and pause
console.log(generator.next()) // { value: 'yeild 2', done: false }
// Execute the third yield and pause
console.log(generator.next()) // { value: undefined, done: true }
Copy the code
2.4 Generator passing parameters – next function
- When we call the next function, we can pass it an argument that will be returned by the yield statement
Example 7:
function * foo() {
const next1 = yield 'yeild 1'
console.log({ next1 }) // { next1: 'next1' }
const next2 = yield 'yeild 2'
console.log({ next2 }) // { next2: 'next2' }
}
const generator = foo() // Returns a generator function that is not executed internally
// Execute the first yield and pause
console.log(generator.next()) // { value: 'yeild 1', done: false }
// Execute the second yield and pause
console.log(generator.next('next1')) // { value: 'yeild 2', done: false }
// Execute the third yield and pause
console.log(generator.next('next2')) // { value: undefined, done: true }
Copy the code
2.5 Generators replace iterators
Generators are special iterators, so can they be used instead of iterators? Yes
function createIterator(arr) {
let index = 0
return {
next: () = > {
if (index < arr.length) {
return { value: arr[index++], done: false}}else {
return { value: undefined.done: true}
}
}
}
}
const names = ['zhangsan'.'li'.'wangwu']
const iterator = createIterator(names)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
Copy the code
This is a function that generates an iterator, which can be used as a generator instead
function * createIterator(arr) {
for(const item of arr) {
yield item
}
}
const names = ['zhangsan'.'li'.'wangwu']
const iterator = createIterator(names)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
Copy the code
We can simplify it a little bit more
- Yield * follows an iterable, equivalent to for.. The syntax of of is used to iterate over the contents of the iterable arR one by one, yielding data each time the next method is called
function * createIterator(arr) {
yield* arr
}
const names = ['zhangsan'.'li'.'wangwu']
const iterator = createIterator(names)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
Copy the code