【问题标题】:What's the purpose of an asterisk (*) in ES6 generator functionsES6 生成器函数中星号 (*) 的用途是什么
【发布时间】:2015-03-02 21:45:43
【问题描述】:

有人可以向我解释一下:为什么 ES6 中的生成器函数用星号标记?

例如,而不是:

function *someGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

我们可以这样写:

function someGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

甚至:

var someGenerator = () => {
    yield 1;
    yield 2;
    yield 3;
}

var someObject = {

    someGenerator() {
        yield 1;
        yield 2;
        yield 3;
    }
}            

JS 编译器可以在解析时检测到someGenerator 包含yield 运算符,并从该函数生成一个生成器。

为什么检测到yield 存在还不够?

【问题讨论】:

  • 我对 ES6 了解不多,但我知道星号并不是 function 关键字独有的。 - 你也可以使用yield*
  • @JamesDonnelly 是的,您可以使用yield*。所以我的问题是为什么编译器无法通过yield(或yield*)的存在检测到该函数是生成器?
  • @limelights - 我把它变红了,但没有找到我的问题的答案。你能指出答案所在的段落吗?
  • 这让我很困惑。从查看 MDN 上的文档来看,星号应该是 function* 而不是 function *。即它紧跟在函数本身而不是函数名本身之后。有区别吗?

标签: javascript ecmascript-6 ecmascript-harmony


【解决方案1】:

三个原因是:

  1. 可读性。生成器与函数完全不同,并且差异应该立即可见(也就是说,无需检查整个实现以寻找产量)。

  2. 一般性。自然应该可以编写不产生,只直接返回的生成器。此外,注释掉正文的一部分(例如用于调试)不应默默地改变某物是否是生成器。

  3. 兼容性。只有严格模式保留 'yield' 作为关键字,但 ES6 的目标是所有新功能也可以在草率模式下使用(恕我直言,这是一个不幸的决定,但尽管如此)。此外,即使在严格模式下,“yield”也存在许多解析细节;例如,考虑默认参数:

    function* g(a = yield(2)) { 'use strict' }
    

    没有*,解析器只能在看到函数体之后才能决定如何解析yield。也就是说,您需要无限的前瞻、回溯或其他骇人听闻的技术来处理这个问题。

我应该注意到(1)和(2)已经足够了。

(完全披露:我是 EcmaScript 委员会的成员。)

【讨论】:

  • 借此机会我想问一下:ECMAScript 委员会有没有关于数组生成器(类似于() *=> { })和对象字面量的生成器方法(类似于var someObject = { *someGenerator() {} })的计划?因为恕我直言function * 有很多符号。如果没有数组生成器,我们必须使用 .bind(this)var that = this,就像在旧 es5 天一样。
  • @alexpods,生成器方法 ({ *g(){} }) 已经在 ES6 中。箭头生成器被讨论过不止一次,但没有人能够提出一致且没有问题的语法。
【解决方案2】:

不允许使用空生成器(没有主体);那么unStarredFunc() 是否应该遵循生成器语义?

出于兼容性原因:

function yield(x) { return x };

function a() { 
    yield (4+1);
};

这在语法上是正确的,但调用 .next() 会导致错误,而添加星号来显式定义生成器会导致 .next().value === 5

在解析时检测 someGenerator 包含 yield 运算符

某些构造在解析时无法解析:

function someGenerator(i) { 
    if (glob) 
        return 4; 
    else 
        yield* anotherGen(i);
}

当然,从function* 的定义中可以更轻松地立即看出它是一个生成器,而无需挖掘其源代码来寻找产量。

【讨论】:

  • 1) 出于兼容性原因 - 是的,我同意。但是您可以在“使用严格”下涵盖新的实现。如果指定的 'use strict' 比 yeild 被解释为运算符。否则,如果实现了该名称的函数,-yield 被解释为函数,您需要在函数中添加星号* 以从中生成生成器。
  • 好答案。顺便说一句,即使是非空函数也可以用作生成器,其中没有yields。它在第一次调用 next 时返回 donereturn 语句的值为 value
  • 2) Some constructs cannot be resolved at parse time - 实际上你的例子是生成器,它可以解析解析时间。逻辑很简单 - yield(或 yield* 存在)它生成器。否则 - 它的功能。毕竟,您仍然无法在当前的 es6 实现中创建条件函数/生成器函数。
  • 我接受你的观点,但会检查严格性,寻找一个名为 yield 的现有函数(可能随时存在)和空生成器的特殊情况听起来比 只需添加一个星号方法。我认为从根本上讲,* 可以作为 new 代码中yield 的保留和行为的切换,因此它不会对任何现有代码造成任何问题。跨度>
  • 我想这就是为什么他们选择了以前的破码符号装饰而不是创建一个新的 Enumerable 关键字
猜你喜欢
  • 2016-09-16
  • 2017-03-24
  • 2016-09-11
  • 2023-04-10
  • 2016-08-26
  • 2017-05-11
  • 2014-02-13
  • 2012-10-04
  • 2017-10-21
相关资源
最近更新 更多