为什么ES6“yield”在此上下文中被调用时是一个保留词?

时间:2021-09-05 23:29:50

I am using node 4.1.1. When I run this code

我使用的是节点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);
}

I get this error

我得到这个错误

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

SyntaxError: Unexpected strict mode reserved word

If I rearrange the code to be this

如果我把代码重新排列成这样

"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);
}

I get the expected result.

我得到了预期的结果。

Why does the second one work, and the first fail? And surely if a keyword is reserved, it's reserved in all contexts, not just when it's used in a arrow function?

为什么第二个有效,第一个失败?如果关键字是保留的,它在所有上下文中都保留,而不只是在箭头函数中使用?

5 个解决方案

#1


7  

It is because arrow functions are not generator functions. For example,

这是因为箭头函数不是生成器函数。例如,

function temp() {
  yield 1;
}

Can we expect this to work? No. Because temp is not a generator function. The same is applicable to arrow functions as well.

我们能指望它起作用吗?不。因为temp不是生成器函数。同样也适用于箭头函数。


FWIW, the usage of yield in an Arrow function is an early error as per the ECMAScript 2015 specification, as per this section,

FWIW,在箭头函数中使用yield是根据ECMAScript 2015规范的早期错误,根据本节,

ArrowFunction : ArrowParameters => ConciseBody

ArrowFunction: ArrowParameters => ConciseBody。

  • It is a Syntax Error if ArrowParameters Contains YieldExpression is true.

    如果ArrowParameters包含屈服表达式,那么它就是一个语法错误。

  • It is a Syntax Error if ConciseBody Contains YieldExpression is true.

    如果ConciseBody包含YieldExpression,则是语法错误。

#2


11  

You can do anything but not everything – Learn to delegate

你可以做任何事,但不能做任何事——学会委派

Let's first look at two examples

让我们先看两个例子

1. yield

1。收益率

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

for (let n of generator([1,2,3])) console.log(n);
// [ 2, 3, 4 ]

Our for loop logs each value yielded by the generator. Inside our generator, we have a single yield call which will yield the result of the numbers.map call, which is a new Array. Because there is only a single yield, the only logged value is [2,3,4]

我们的for循环记录生成器生成的每个值。在我们的生成器中,我们有一个单一的收益率调用,它将产生数字的结果。映射调用,这是一个新的数组。因为只有一个收益率,所以记录的唯一值是[2,3,4]

2. yield*

2。产量*

So yield obviously won't work in the case above. We'll have to try something else.

显然,收益率在上面的情况下是行不通的。我们得试试别的。

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

for (let n of generator([1,2,3])) console.log(n);
// 2
// 3
// 4

Again, our for loop logs each value yielded by the generator. Inside our generator, we yield the same result of the numbers.map call, but this time we use yield*, which yield by delegation.

同样,我们的for循环记录生成器生成的每个值。在我们的生成器中,我们产生了相同的结果。map调用,但这次我们使用yield*,按委托授予。

What are we yielding then? Well, Array's have a built-in generator, Array.prototype[Symbol.iterator]. So at this point, the for loop is essentially directly stepping thru the generator provided by the Array. Since the array has 3 values, we see 3 logged values.

那么,我们屈服于什么呢?数组有一个内置的生成器,Array.prototype[Symbol.iterator]。在这一点上,for循环实际上是直接通过数组提供的生成器进行步进。由于数组有3个值,所以我们看到3个日志值。


Watchful eyes

警惕的眼睛

So we iterate thru numbers once using Array.prototype.map but then we iterate thru the intermediate array using the for loop? Seems like a waste doesn't it?

我们使用array。prototype对数据进行迭代。映射,然后我们用for循环遍历中间数组?看起来像是浪费,不是吗?

Let's look back at your original code though

让我们回头看看你的原始代码。

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

for (var n of generator()) {
  console.log(n);
}

Notice that your numbers.map call is pretty meaningless. Array.prototype.map creates a new array, but your generator doesn't do anything with it. So really you're just using map to iterate thru the numbers, not because you actually care about the returned value of map

注意您的数字。地图调用毫无意义。Array.prototype。map创建了一个新的数组,但是您的生成器不会对它做任何事情。你只是用map来迭代数字,不是因为你关心的是map的返回值


Say what you mean, mean what you say

说出你的意思,说出你的意思

OK, so now we know we only really care about iterating thru the numbers. So we'll use iteration the way JavaScript knows best

好了,现在我们知道我们只关心遍历这些数字。因此我们将使用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

Bingo. No tricky yield*. No double iteration. No nonsense.

宾果。没有复杂的收益率。没有双迭代。没有废话。

#3


4  

That's because the arrow function is not a generator. If I expand your arrow function, it would look something like:

这是因为箭头函数不是生成器。如果我展开你的箭头函数,它会是这样的

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));
}

#4


0  

Just discovered you can encounter this by accidentally closing your function too early.

刚刚发现,您可能会因为不小心过早地关闭函数而遇到这种情况。

i.e. one too many }

即一个过多的}

#5


0  

[1,2,3,4,5].map(function*(v){yield v+1;}).reduce((accumulator, currentValue) => accumulator = [...accumulator].concat([...currentValue]))

explanation...

解释……

[1,2,3,4,5].map(function*(v){yield v+1;})

pack all values into generator resulting

将所有值打包到生成器中

(5) [Generator, Generator, Generator, Generator, Generator]

(5)[发电机、发电机、发电机、发电机、发电机]

unpack into flat array

解压缩到平面阵列

.reduce((accumulator, currentValue) => accumulator = [...accumulator].concat([...currentValue]))

(5) [2, 3, 4, 5, 6]

(5)[2,3,4,5,6]

for normal use

对正常使用

[1,2,3,4,5].map(function*(v){yield v+1;}).forEach(v => console.log([...v][0]))

2

2

3

3

4

4

5

5

6

6

[...v][0] is a bit ugly but it is works.

[…[0]有点难看,但很管用。

#1


7  

It is because arrow functions are not generator functions. For example,

这是因为箭头函数不是生成器函数。例如,

function temp() {
  yield 1;
}

Can we expect this to work? No. Because temp is not a generator function. The same is applicable to arrow functions as well.

我们能指望它起作用吗?不。因为temp不是生成器函数。同样也适用于箭头函数。


FWIW, the usage of yield in an Arrow function is an early error as per the ECMAScript 2015 specification, as per this section,

FWIW,在箭头函数中使用yield是根据ECMAScript 2015规范的早期错误,根据本节,

ArrowFunction : ArrowParameters => ConciseBody

ArrowFunction: ArrowParameters => ConciseBody。

  • It is a Syntax Error if ArrowParameters Contains YieldExpression is true.

    如果ArrowParameters包含屈服表达式,那么它就是一个语法错误。

  • It is a Syntax Error if ConciseBody Contains YieldExpression is true.

    如果ConciseBody包含YieldExpression,则是语法错误。

#2


11  

You can do anything but not everything – Learn to delegate

你可以做任何事,但不能做任何事——学会委派

Let's first look at two examples

让我们先看两个例子

1. yield

1。收益率

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

for (let n of generator([1,2,3])) console.log(n);
// [ 2, 3, 4 ]

Our for loop logs each value yielded by the generator. Inside our generator, we have a single yield call which will yield the result of the numbers.map call, which is a new Array. Because there is only a single yield, the only logged value is [2,3,4]

我们的for循环记录生成器生成的每个值。在我们的生成器中,我们有一个单一的收益率调用,它将产生数字的结果。映射调用,这是一个新的数组。因为只有一个收益率,所以记录的唯一值是[2,3,4]

2. yield*

2。产量*

So yield obviously won't work in the case above. We'll have to try something else.

显然,收益率在上面的情况下是行不通的。我们得试试别的。

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

for (let n of generator([1,2,3])) console.log(n);
// 2
// 3
// 4

Again, our for loop logs each value yielded by the generator. Inside our generator, we yield the same result of the numbers.map call, but this time we use yield*, which yield by delegation.

同样,我们的for循环记录生成器生成的每个值。在我们的生成器中,我们产生了相同的结果。map调用,但这次我们使用yield*,按委托授予。

What are we yielding then? Well, Array's have a built-in generator, Array.prototype[Symbol.iterator]. So at this point, the for loop is essentially directly stepping thru the generator provided by the Array. Since the array has 3 values, we see 3 logged values.

那么,我们屈服于什么呢?数组有一个内置的生成器,Array.prototype[Symbol.iterator]。在这一点上,for循环实际上是直接通过数组提供的生成器进行步进。由于数组有3个值,所以我们看到3个日志值。


Watchful eyes

警惕的眼睛

So we iterate thru numbers once using Array.prototype.map but then we iterate thru the intermediate array using the for loop? Seems like a waste doesn't it?

我们使用array。prototype对数据进行迭代。映射,然后我们用for循环遍历中间数组?看起来像是浪费,不是吗?

Let's look back at your original code though

让我们回头看看你的原始代码。

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

for (var n of generator()) {
  console.log(n);
}

Notice that your numbers.map call is pretty meaningless. Array.prototype.map creates a new array, but your generator doesn't do anything with it. So really you're just using map to iterate thru the numbers, not because you actually care about the returned value of map

注意您的数字。地图调用毫无意义。Array.prototype。map创建了一个新的数组,但是您的生成器不会对它做任何事情。你只是用map来迭代数字,不是因为你关心的是map的返回值


Say what you mean, mean what you say

说出你的意思,说出你的意思

OK, so now we know we only really care about iterating thru the numbers. So we'll use iteration the way JavaScript knows best

好了,现在我们知道我们只关心遍历这些数字。因此我们将使用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

Bingo. No tricky yield*. No double iteration. No nonsense.

宾果。没有复杂的收益率。没有双迭代。没有废话。

#3


4  

That's because the arrow function is not a generator. If I expand your arrow function, it would look something like:

这是因为箭头函数不是生成器。如果我展开你的箭头函数,它会是这样的

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));
}

#4


0  

Just discovered you can encounter this by accidentally closing your function too early.

刚刚发现,您可能会因为不小心过早地关闭函数而遇到这种情况。

i.e. one too many }

即一个过多的}

#5


0  

[1,2,3,4,5].map(function*(v){yield v+1;}).reduce((accumulator, currentValue) => accumulator = [...accumulator].concat([...currentValue]))

explanation...

解释……

[1,2,3,4,5].map(function*(v){yield v+1;})

pack all values into generator resulting

将所有值打包到生成器中

(5) [Generator, Generator, Generator, Generator, Generator]

(5)[发电机、发电机、发电机、发电机、发电机]

unpack into flat array

解压缩到平面阵列

.reduce((accumulator, currentValue) => accumulator = [...accumulator].concat([...currentValue]))

(5) [2, 3, 4, 5, 6]

(5)[2,3,4,5,6]

for normal use

对正常使用

[1,2,3,4,5].map(function*(v){yield v+1;}).forEach(v => console.log([...v][0]))

2

2

3

3

4

4

5

5

6

6

[...v][0] is a bit ugly but it is works.

[…[0]有点难看,但很管用。