JS生成器代码示例

JS的生成器的一些代码示例,示例中有详细注释,用于理解:

// EX1=======================================================>
console.log("EX1=======================================================>");
function* foo1(x) {
    console.log("run foo2");
    var y = x * (yield 5);
    return y + 10;
}
var it = foo1(6); //此时并没有运行foo1(),只是构造了一个迭代器
console.log("create Iterator");


// 启动foo1(..),foo1()在yield语句处暂停,在这一点上第一个it.next()调用结束。
// 此时*foo1()仍在运行并且是活跃的,但处于暂停状态。
// 只有暂停的yield才能接受这样一个通过next(..)传递的值,
// 而在生成器的起始处我们调用第一个next()时,还没有暂停的yield来接受这样一个值。
// 规范和所有兼容浏览器都会默默丢弃传递给第一个next()的任何东西。
// 传值过去仍然不是一个好思路,因为你创建了沉默的无效代码,这会让人迷惑。
// 因此,启动生成器时一定要用不带参数的next()
console.log("skk => it.next()", it.next());
console.log("skk => it.next(7):", it.next(7)); // 52

// EX2=======================================================>
console.log("EX2=======================================================>");

// yield..和像a = 3这样的赋值表达式有同样的“表达式优先级”——类似于运算符优先级的概念。
// 这意味着yield..基本上可以出现在任何a = 3合法出现的位置。
// 因为yield关键字的优先级很低,且是右结合的。
function* foo2() {
    console.log("启动foo2");
    var a, b;

    a = 3; // 合法
    // b = 2 + a = 3;          // 不合法
    b = 2 + (a = 3); // 合法
    yield 1; // 合法
    console.log("yield 1, a= ", a);
    // a = 2 + yield 1;        // 不合法
    a = 2 + (yield 2); // 合法
    console.log("yield 2, a=", a);
    return a;
}

var it = foo2();
console.log("ready next1");
console.log("next 1", it.next());
console.log("ready next2");
console.log("next 2", it.next());
console.log("ready next3");
console.log("next 3", it.next(5)); // 传参是合适的

// EX3=======================================================>
console.log("EX3=======================================================>");
// 执行生成器,比如foo(),并不实际在生成器中运行代码。相反,它会产生一个迭代器控制这个生成器执行其代码
function* foo3() {
    console.log("inside 1 *foo3():", yield "B");

    console.log("inside 2 *foo3():", yield "C");

    return "D";
}

function* bar3() {
    console.log("inside 1 *bar3():", yield "A");

    // yield委托!
    console.log("inside 2 *bar3():", yield* foo3());

    console.log("inside 3 *bar3():", yield "E");
    // yield委托!
    console.log("inside 4 *[1,2,7]:", yield* [1, 2, 7]);

    return "F";
}

var it = bar3();

console.log("outside:", it.next());
// outside: A

console.log("outside:", it.next(11));
// inside 1*bar(): 11
// outside: B

console.log("outside:", it.next(22));
// inside 1*foo(): 22
// outside: C

console.log("outside:", it.next(33));
// inside 2*foo(): 33
// inside 2*bar(): D
// outside: E

console.log("outside:", it.next(44));
// inside 3*bar(): 44
// outside: 1
console.log("outside:", it.next(55));
// outside: 2
console.log("outside:", it.next(66));
// outside: 3
console.log("outside:", it.next(77));
// inside 4 *[1,2,7]: undefined
// outside: F

// EX4=======================================================>
console.log("EX4=======================================================>");
function* foo4() {
    console.log("foo4 run");
    var arr = [yield 11, yield 22, yield 33]; //即使声明了也要用next
    // console.log( arr, yield 4 );
    console.log("foo4 return");
    return "dk";
}

var it = foo4();
console.log("next 1", it.next());
console.log("next 2", it.next());
console.log("next 3", it.next());
console.log("next 4", it.next());

// EX5=======================================================>
console.log("EX5=======================================================>");

function* foo5(x) {
    if (x < 3) {
        x = yield* foo5(x + 1);
    }
    console.log("foo5 out x=", x);
    return x * 2;
}
var it = foo5(1);
// 执行next后生成器没有真正暂停,因为并没有yield ..表达式。
// 相反,yield *只是通过递归调用保存当前的迭代步骤。所以,只要一次调用迭代器的next()函数就运行了整个生成器
console.log("it.next =", it.next()); // { value: 24, done: true }

// EX6=======================================================>
console.log("EX6=======================================================>");

// 迭代器的本质
// 每个yield..从(1, 2, 3)中发出一个值,更直接地说,它是暂停生成器来等待一个值。
// 换句话说几乎等价于在问 "这里我应该用什么值?请回复"
function *foo6() {
    var x = yield 1;
    var y = yield 2;
    var z = yield 3;
    console.log("foo6 return",  x, y, z );
}
// 生成器函数引用(比如foo6)自己并不是一个iterable, 需要通过foo6()执行它才能得到一个迭代器
for (var v of foo6()) {
    console.log( "v=", v ); // 如果yield后面是变量的话,则返回undefined
}

// 创建迭代器
var it = foo6();
// 第一个next()调用初始的暂停状态启动生成器,运行直到第一个yield。在调用第一个next()的时候,
// 并没有yield..表达式等待完成。如果向第一个next()调用传入一个值,这个值会马上被丢弃,因为并没有yield等待接收这个值
console.log("next 1", it.next()); // next 1 { value: 1, done: false }

// 需要给x一个什么值?给“XX”吧
console.log("next 2", it.next("XX")); // next 2 { value: 2, done: false }

// 需要给y一个什么值?给“YY”吧
console.log("next 3", it.next("YY")); // next 3 { value: 3, done: false }

// 需要给z一个什么值?给“ZZ”吧
console.log("next 4", it.next("ZZ")); // next 4 { value: undefined, done: true }, foo6没有return值,value为undefined

最后更新于 2023-11-17 16:33:17 by twotwolucky

发表评论