【问题标题】:SyntaxError: Unexpected Identifier (Generators in ES6)SyntaxError: Unexpected Identifier (ES6 中的生成器)
【发布时间】:2019-05-08 17:30:20
【问题描述】:

我在阅读documentation on generators from MDN后想出了这个简单的实验:

var nodes = {
    type: 'root',
    value: [
        { type: 'char', value: 'a' },
        { type: 'char', value: 'b' },
        { type: 'char', value: 'c' },
    ],
};

function* recursiveGenerator(node) {
    if (node.type === 'root') {
        node.value.forEach(function (subnode) {
            for (var suffix of recursiveGenerator(subnode)) {
                yield suffix;
            }
        });
    }

    else {
        yield node.value;
    }
}

for (generated of recursiveGenerator(nodes)) {
    console.log(generated);
}

在带有--harmony 标志集的node.js v0.11.9 上运行它会产生以下错误:

alix@900X4C:~$ node --version
v0.11.9
alix@900X4C:~$ node --harmony test.js 

/home/alix/test.js:14
                yield suffix;
                      ^^^^^^
SyntaxError: Unexpected identifier

我也尝试使用for ... in ...let 关键字代替var,但没有任何成功。

我不明白 what yield* does exactly,但如果我在 for 循环中使用它,我会得到:

alix@900X4C:~$ node --harmony test.js 

/home/alix/test.js:14
                yield* suffix;
                ^
ReferenceError: yield is not defined

如果我将 for 中的 yield 替换为 console.log(),它会输出 abc。我做错了什么?


编辑

这是一个简约的生成器,表明 node.js 知道如何使用生成器:

function* alpha() {
    yield 'a';
    yield 'b';
    yield 'c';
}

for (var suffix of alpha()) {
    console.log(suffix);
}

输出:

alix@900X4C:~$ node --harmony y.js 
a
b
c

解决方案(感谢@Andrew)

function* recursiveGenerator(node) {
    if (node.type === 'root') {
        for (var i = 0; i < node.value.length; ++i) {
            var subnode = node.value[i];

            for (var suffix of recursiveGenerator(subnode)) {
                yield suffix;
            }
        }
    }

    else {
        yield node.value;
    }
}

for (generated of recursiveGenerator(nodes)) {
    console.log(generated);
}

【问题讨论】:

  • 我对这里随机出现的*s 有点困惑。这些实际上在您的代码中吗?它们似乎不是您链接的规范的一部分。
  • @ChrisHayes:我添加了另一个链接(在问题中查找yield*)。据我所知,function* ... 是一个生成器函数(即包含 yield 关键字的函数),yield* 是将生成器委托给另一个生成器的方式(我无法让它工作)。跨度>
  • 知道了,谢谢。对于yield*,从错误消息来看,我认为节点期望yield 是一个变量名。在这两种情况下,我肯定认为它没有被识别为关键字。
  • 我对生成器还不够熟悉,因此无法发布答案,但我相信您的问题出在forEach()。这会创建自己的范围(如setTimeout())。如果您将其更改为 for (var i = 0; i &lt; node.value.length; i++),您应该会看到它工作正常。
  • @Andrew 好地方。海事组织值得回答。好奇该节点在这里没有输出更好的错误消息,但我想yield 还为时过早。

标签: javascript node.js generator yield ecmascript-harmony


【解决方案1】:

总结 cmets:不能在 常规 函数中使用 yield,因此不能将 yieldforEach 一起使用。这里是“生成”foreach 的示例:

function * foreach (arr, fn) {
  var i

  for (i = 0; i < arr.length; i++) {
    yield * fn(arr[i])
  }
}

function * gen (number) {
  yield number + 1
  yield number + 2
  yield number + 3
}

function * other () {
  yield * foreach([1, 2, 3], gen)
}

for (var i of other()) {
    console.log(i)
}

更新 使用这样的助手也可以非常优雅地解决原始问题:

var nodes = {
  type: 'root',
  value: [
    { type: 'char', value: 'a' },
    { type: 'char', value: 'b' },
    { type: 'root', value: [
        { type: 'char', value: 'c' },
        { type: 'char', value: 'd' },
        { type: 'char', value: 'e' },
      ] 
    },
  ],
}

function * foreach (arr, fn) {
  var i

  for (i = 0; i < arr.length; i++) {
    yield * fn(arr[i])
  }
}

function * value (val) {
  yield val
}

function * recursiveGenerator(node) {
  yield * node.type === 'root' ?  foreach(node.value, recursiveGenerator) : value(node.value)
}

for (var generated of recursiveGenerator(nodes)) {
  console.log(generated);
}

所以生成器本身就变成了单行!

【讨论】:

  • *您不能在函数* That's misleading. Inside a generator function is the *only* place you can use yield 中使用yield。但是,为示例代码 +1。
  • @ChrisHayes:会修复它。 =) 感谢您的示例,yield* 实际上确实有助于理解它的作用。
  • @ChrisHayes 究竟是什么误导?生成器函数是唯一可以使用 yield => 你可以在函数内部使用 yield 的地方。或者你的意思是说“你不能在非生成器函数中使用yield”这样的说法更好?
  • @vkurchatkin 是的,这就是我的意思。抱歉,我的评论在那里令人困惑。
【解决方案2】:

您已经找到了您的解决方案,但为了记录,这里是另一个稍微不同的示例,它打印树中所有节点的类型(我添加了一些深度和变量)

var nodes = {
    type: 'root',
    value: [
        { type: 'char', value: 'a' },
        { type: 'char', value: 'b' },
        { type: 'char', value: [{type: 'int', value: 'c'}] },
    ],
};

var flattenTree = function* (root) {
    yield root.type;
    var subvalues = root.value;
    for(var i in subvalues) {
        var gen = flattenTree(subvalues[i]);
        val = gen.next();
        while(!val.done) {
            if(val.value != undefined)
                yield val.value;
            val = gen.next();
        }
    }
}

var printTree = function() {
    console.log("begin tree");
    var generator = flattenTree(nodes);
    var next = generator.next();
    while(!next.done) {
        console.log(next);
        next = generator.next();
    }
    console.log("finish tree");
}

printTree();

输出:

~/workspace/tmp$ ../node/node --harmony test-gen.js 
begin tree
{ value: 'root', done: false }
{ value: 'char', done: false }
{ value: 'char', done: false }
{ value: 'char', done: false }
{ value: 'int', done: false }
finish tree

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-06
    • 2021-06-09
    • 1970-01-01
    • 2017-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多