在JavaScript中,生成器函数中的返回值应始终不返回任何内容吗?

问题描述 投票:3回答:1

换句话说,生成器函数中的return someValue是反模式吗?

.next()可以显示{ value: 3, done: true }

function* genFn() {
  yield 1;
  yield 2;
  return 3;
}

const iter = genFn();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

但如果用作可迭代项,则不会:

function* genFn() {
  yield 1;
  yield 2;
  return 3;
}

const iter = genFn();
console.log([...iter]);

[似乎使用return value或不使用return,意味着return undefined,如果它是可迭代协议,因此也是迭代器协议,则不使用该值。

javascript ecmascript-6 generator anti-patterns
1个回答
1
投票

换句话说,生成器函数中的return someValue是反模式吗?

不,但是您应该仅在有意义时使用它。除了手动调用.next()之外,还会产生yield*

function* a() {
    yield 1;
    yield 2;
    return 3;
}

function* b() {
    console.log(yield* a());
}

console.log([...b()]);

一个非常实际的例子是异步功能,其中yield可以用作await,而您仍然想返回一个值。当编写并非基于承诺/可移植物的相似模式时,同样的概念仍然适用。

不受JavaScript调用堆栈限制的递归,例如:

function* sillyAdd(a, b) {
    return b === 0
        ? a
        : yield sillyAdd(a + 1, b - 1);
}

const restack = f => (...args) => {
    const stack = [f(...args)];
    let ret = undefined;

    while (stack.length !== 0) {
        let {value, done} = stack[stack.length - 1].next(ret);

        if (done) {
            stack.pop();
            ret = value;
        } else {
            stack.push(value);
        }
    }

    return ret;
};

console.log(restack(sillyAdd)(2, 100000));
console.log('(it’s synchronous)');

通过在暂停的功能中保持状态进行在线解析:

function* isBalanced() {
    let open = 0;

    for (let c; c = yield;) {
        if (c === '(') {
            open++;
        } else if (c === ')') {
            open--;

            if (open < 0) {
                return false;
            }
        }
    }

    return open === 0;
}

class Parser {
    constructor(generator) {
        this.generator = generator();
        this.generator.next();
        this.done = false;
        this.result = null;
    }

    write(text) {
        if (this.done) {
            return;
        }

        for (const c of text) {
            const {value, done} = this.generator.next(c);

            if (done) {
                this.done = true;
                this.result = value;
                break;
            }
        }
    }

    finish() {
        if (this.done) {
            return this.result;
        }

        return this.generator.next().value;
    }
}

const p = new Parser(isBalanced);

const chunk = '()'.repeat(1000);

for (let i = 0; i < 100; i++) {
    p.write(chunk);
}

console.log(p.finish());
© www.soinside.com 2019 - 2024. All rights reserved.