ES6中的Generator函数与yield
generator函数是为了解决异步编程的函数,generator函数会返回一个可迭代对象(也就是可遍历的对象)。
形式上,Generator 函数声明方法和普通函数颇有相似之处,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
function* num() {
yield "111";
yield "222";
yield "333";
}
const iterator = num();
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
/*
上述代码执行结果,generator函数是为了进行异步操作,而不会同步执行,
代码内部被yield分隔,分隔的代码块为:yield的数量 + 1,generator函数并不会自己自动执行,而是需要调用next方法来执行
调用next()方法会产生一个指针,第一个next()方法就执行第一个yield,当调用第二个yield时指针便会移动到第二个yield上,以此来遍历generator函数
generator函数会返回一个迭代器对象,那么我们可以通过for of来进行遍历
{value: '111', done: false}
{value: '222', done: false}
{value: '333', done: false}
{value: undefined, done: true}
*/
for (const v of iterator) {
// console.log('遍历generator的每一项:',v);
}
/*
上述代码遍历结果,所遍历的每一项都是调用next()n方法后所返回的对象中的value的值也就是yield后面的值
遍历generator的每一项: 111
遍历generator的每一项: 222
遍历generator的每一项: 333
*/
// 同样generator函数也和普通函数一样可以进行传参,同样next()方法也可以传参
function* animal(args) {
console.log("所接收到的参数:", ...args);
yield "猴子";
yield "大象";
yield "海豹";
}
const animalGenerator = animal(["🐉", "🐍", "🐎", "🐏"]);
// 如果只是单单调用generator函数,函数并不会进行执行,如果想要输出结果就必须要调用next()方法
animalGenerator.next();
// 对next()方法进行传参
function* phone() {
const res1 = yield "Huawei";
console.log(res1);
const res2 = yield "xiaomi";
console.log(res2);
const res3 = yield "oppo";
console.log(res3);
}
const phoneSort = phone();
phoneSort.next("aaa");
phoneSort.next("bbb");
phoneSort.next("ccc");
phoneSort.next("ddd");
/*
上述代码执行结果:
bbb
ccc
ddd
可以发现我们给next()方法传参,传入了四个参数但是只打印了3个参数,这表明我们给next()方法进行传参的时候,传入的参数并不会被与之匹配的yield所接收
而是成为了上一个yield的返回值,所以我们的res1并没有打印aaa而是打印的bbb
*/
// 比较 yield与yield *
function* generatorOne() {
yield ["a", "b", "c"];
}
function* generatorTwo() {
// yield* ["a", "b", "c"];
yield 'a'
yield 'b'
yield 'c'
}
const one = generatorOne()
const two = generatorTwo()
console.log(one.next().value);
console.log(two.next().value);
/*
使用yield* 的打印结果:
['a', 'b', 'c']
a
全部使用yield的打印结果:
['a', 'b', 'c']
a
可以发现两者打印结果一摸一样
我们可以得出结论: yield* ['a','b','c']等价于 yield 'a'; yield 'b'; yield 'c';
*/
例题:
// 下面标注英文的位置应该输入什么样的代码,obj.next()才会是下面的内容
// 例题:
const teams = [
{name: 'Team 1', members: ['Paul', 'Lisa']},
{name: 'Team 2', members: ['Laura', 'Tim']},
]
// generator函数会返回一个可迭代对象
function * getMembers(members) {
for (let i = 0; i < members.length; i++) {
yield members[i]
}
}
function * getTeams(teams) {
for (let i = 0; i< teams.length; i++) {
// somthing is missing here
}
}
const obj = getTeams(teams)
obj.next() // {value: "Paul", done: false}
obj.next() // {value: "Lisa", done: false}
const teams = [
{name: 'Team 1', members: ['Paul', 'Lisa']},
{name: 'Team 2', members: ['Laura', 'Tim']},
]
// generator函数会返回一个可迭代对象
function * getMembers(members) {
for (let i = 0; i < members.length; i++) {
yield members[i]
}
}
function * getTeams(teams) {
for (let i = 0; i< teams.length; i++) {
// somthing is missing here
yield* getMembers(teams[i].members)
// console.log(getMembers(teams[i].members));
// let iterator = getMembers(teams[i].members)
// 第一次循环所返回的可迭代对象相当于
/*
yield 'Paul'
yield 'Lisa'
*/
// 第二次循环所返回的可迭代对象相当于
/*
yield 'Laura'
yield 'Tim'
*/
// 所以 yield * getMembers(teams[i].members)相当于
/*
yield * ['Paul', 'Lisa', 'Laura', 'Tim']
*/
for (const v of iterator) {
// console.log(v);
}
// 判断这个循环执行了几次,是同步执行还是异步执行
// console.log(i);
}
}
const obj = getTeams(teams)
// for of循环遍历一下generator对象:obj
for (const item of obj) {
console.log(item);
}
// obj.next() // {value: "Paul", done: false}
// obj.next() // {value: "Lisa", done: false}
我们通过打印发现getMembers()函数每一次都会返回一个generator对象,里面的值正是teams中的members中的值,那么最后的值等价于
yield * ['Paul', 'Lisa', 'Laura', 'Tim']