为什么在这种情况下调用ES6会"产生"一个保留字?

Mik*_*gan 15 javascript node.js ecmascript-6

我正在使用节点4.1.1.当我运行此代码时

"use strict";

function *generator() {
  let numbers = [1,2,3,4,5];
  numbers.map(n => yield (n + 1));
}

for (var n of generator()) {
  console.log(n);
}
Run Code Online (Sandbox Code Playgroud)

我收到这个错误

  numbers.map(n => yield (n + 1));
                   ^^^^^

SyntaxError: Unexpected strict mode reserved word
Run Code Online (Sandbox Code Playgroud)

如果我将代码重新排列为此

"use strict";

function *generator() {
  let numbers = [1,2,3,4,5];
  let higherNumbers = numbers.map(n => n + 1);
  for(let i=0;i<higherNumbers.length;i++) {
    yield higherNumbers[i];
  }
}

for (var n of generator()) {
  console.log(n);
}
Run Code Online (Sandbox Code Playgroud)

我得到了预期的结果.

为什么第二个工作,第一个失败?当然,如果关键字被保留,它会在所有上下文中保留,而不仅仅是在箭头函数中使用它?

Tha*_*you 13

你可以做任何事情而不是一切 - 学会委派

我们先来看两个例子

产量

function* generator(numbers) {
  yield numbers.map(x => x + 1);
}

for (let n of generator([1,2,3])) console.log(n);
// [ 2, 3, 4 ]
Run Code Online (Sandbox Code Playgroud)

我们的for循环记录了生成器产生的每个值.在我们的生成器中,我们有一个yield调用,它将产生调用的结果numbers.map,这是一个新的数组.因为只有一个产量,所以唯一记录的值是[2,3,4]

2. yield*

所以yield在上面的情况下显然不会起作用.我们必须尝试别的东西.

function* generator(numbers) {
  yield* numbers.map(x => x + 1);
}

for (let n of generator([1,2,3])) console.log(n);
// 2
// 3
// 4
Run Code Online (Sandbox Code Playgroud)

同样,我们的for循环记录yield了生成器编辑的每个值.在我们的生成器中,我们产生相同的numbers.map调用结果,但这次我们使用yield*,通过委托产生.

那我们收获的是什么?那么,Array有一个内置的发生器,Array.prototype[Symbol.iterator].所以在这一点上,for循环基本上直接通过Array提供的生成器步进.由于数组有3个值,我们看到3个记录值.


注视着眼睛

所以我们迭代numbers一次使用Array.prototype.map然后我们使用循环迭代中间数组for?好像浪费不是吗?

让我们回顾一下您的原始代码

function *generator() {
  let numbers = [1,2,3,4,5];
  numbers.map(n => yield (n + 1));
}

for (var n of generator()) {
  console.log(n);
}
Run Code Online (Sandbox Code Playgroud)

请注意,您的numbers.map通话毫无意义.Array.prototype.map创建一个新数组,但你的生成器不会对它任何事情.所以真正你仅仅使用map迭代通的数字,不是因为你真正关心的返回值map


说出你的意思,就是你所说的

好的,现在我们知道我们只关心通过数字迭代.所以我们将按照JavaScript最了解的方式使用迭代

function* generator(numbers) {
  for (let x of numbers)
    yield x + 1
}

for (let n of generator([1,2,3])) console.log(n);
// 2
// 3
// 4
Run Code Online (Sandbox Code Playgroud)

答对了.没有棘手yield*.没有双重迭代.没有废话.


the*_*eye 12

这是因为箭头功能不是发电机功能.例如,

function temp() {
  yield 1;
}
Run Code Online (Sandbox Code Playgroud)

我们可以期待这个吗?temp不.因为不是发电机功能.这同样适用于箭头功能.


FWIW,根据yieldECMAScript 2015规范,在Arrow函数中的使用是一个早期错误,根据本节,

ArrowFunction:ArrowParameters => ConciseBody

  • 如果ArrowParameters包含YieldExpressiontrue,则为语法错误.

  • 如果ConciseBody包含YieldExpressiontrue,则为语法错误.


Jos*_*eph 5

那是因为箭头函数不是生成器。如果我扩展您的箭头功能,它将类似于:

function *generator() {      // <-- this is your generator function
  let numbers = [1,2,3,4,5];
  numbers.map(function(n){   // <-- this one isn't a generator
    yield (n + 1)            // <-- there's your yield
  }.bind(this));
}
Run Code Online (Sandbox Code Playgroud)