ES6生成器(Generator)
Generator
是一个特殊的函数,函数体内部使用yield
表达式,定义不同的内部状态,当执行Generator
函数时,不会直接执行函数体,而是会返回一个遍历器对象(iterator)。
Generator
函数内部可以使用yield
表达式,定义内部状态function
关键字与函数名之间有一个*
function* generator() {
console.log('start');
yield 1
yield 2
yield 3
console.log('end')
}
const iterator = generator() // 这时函数体并没有被执行,而是创建了一个iterator
// 当调用iterator的next方法时,函数体开始执行,
iterator.next() // 'start' {value: 1, done: false}
iterator.next() // {value: 2, done: false}
iterator.next() // {value: 3, done: false}
iterator.next() // 'end' {value: undefined, done: true}
- 每调用一次
next
方法,函数体会从函数头部或上次停下来的地方开始执行,直到遇到下一个yield
表达式或者return
语句时停止 yield
表达式后面的值会作为next
方法返回的对象的value
属性值return
会作为iterator
结束的标记,并且return
的值会作为next
方法返回的对象的value属性值
改写一下上面的例子
function* generator() {
yield 1
yield 2
return 3
}
const iterator = generator()
// 当调用iterator的next方法时,函数体开始执行,
iterator.next() // {value: 1, done: false}
iterator.next() // {value: 2, done: false}
iterator.next() // {value: 3, done: true}
Generator
函数生成的iterator
可以被for...of
遍历
function* generator() {
yield 1
yield 2
yield 3
}
const iterator = generator()
typeof iterator[Symbol.iterator] // 'function'
for (const val of iterator) {
console.log(val)
}
// 1
// 2
// 3
在这里我们只需要知道Generator
函数会生成一个iterator
就够了,但实际上Generator
函数远不止这些,这里我们不做详细介绍了,感兴趣的同学可以看看阮一峰Generator教程
一个对象怎么让它可迭代
添加一个名为 Symbol.iterator
的方法,返回一个迭代器(实现next方法)。
为了让 对象可迭代,我们需要为对象添加一个名为 Symbol.iterator
的方法。当 for..of
循环启动时,它会调用这个方法(如果没找到,就会报错)。这个方法必须返回一个 迭代器(iterator) —— 一个有 next 方法的对象。从此开始,for..of
仅适用于这个被返回的对象。当 for..of
循环希望取得下一个数值,它就调用这个对象的 next()
方法。next()
方法返回的结果的格式必须是 {done: Boolean, value: any}
,当 done=true
时,表示迭代结束,否则 value
是下一个值。
Iterable(可迭代对象)
Iterable 是指有 [Symbol.iterator]
属性的对象,这个属性 obj[Symbol.iterator]
就是 Iterator(迭代器)。也可以说可迭代对象是实现了 Symbol.iterator
方法的对象。
可迭代对象可以被 for..of
循环遍历,我们最常进行迭代操作的可迭代对象就是 Array,其实还有其他可迭代对象,例如 String、Set、Map、函数的 arguments 对象和 NodeList 对象等,这些对象都有默认的 Symbol.iterator
属性。
Iterator(迭代器)
Iterator 必须有 next()
方法,它每次返回一个 {done: Boolean, value: any}
对象,这里 done:true
表明迭代结束,否则 value
就是下一个要迭代的值。
let someString = "hi";
typeof someString[Symbol.iterator]; // "function"
let iterator = someString[Symbol.iterator]();
iterator + ""; // "[object String Iterator]"
iterator.next(); // { value: "h", done: false }
iterator.next(); // { value: "i", done: false }
iterator.next(); // { value: undefined, done: true }