O que é "função *" em JavaScript?

243

Em esta página eu encontrei um novo tipo de função JavaScript:

// NOTE: "function*" is not supported yet in Firefox.
// Remove the asterisk in order for this code to work in Firefox 13 

function* fibonacci() { // !!! this is the interesting line !!!
    let [prev, curr] = [0, 1];
    for (;;) {
        [prev, curr] = [curr, prev + curr];
        yield curr;
    }
}

Eu já sei o que yield, lete [?,?]=[?,?]fazer , mas não tenho idéia o que o function*pretende ser. O que é isso?

O PS não se incomoda em tentar o Google, é impossível procurar expressões com asteriscos ( eles são usados ​​como espaços reservados ).

QNA da cadeia
fonte
4
O comentário no exemplo é bastante antigo agora, a function*sintaxe é suportada no Firefox desde a v26: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… *. As versões anteriores usavam uma sintaxe diferente.
Nickolay
39
Em relação ao Google, basta procurar por "function star" ou "function asterisk". Foi assim que encontrei esta pergunta;).
trysis 02/02
2
Parece que o *foi retirado do link de @Nickolay. Aqui está um link diretamente function*no MDN . Com certeza, suporte "básico" desde a v26 .
Ruffin
Outro link MDN (que, a propósito, eu encontrei na página MDN vinculada pelo OP) : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
BlueRaja - Danny Pflughoeft

Respostas:

199

É uma função de gerador .

Geradores são funções que podem ser encerradas e posteriormente reinseridas. Seu contexto (ligações variáveis) será salvo nas reentrâncias.

Chamar uma função de gerador não executa seu corpo imediatamente; um objeto iterador para a função é retornado. Quando o next()método do iterador é chamado, o corpo da função do gerador é executado até a primeira yieldexpressão, que especifica o valor a ser retornado do iterador ou, com yield*, delega para outra função do gerador.


Nota histórica:

É uma sintaxe proposta para EcmaScript.next.

Dave Herman, da Mozilla, falou sobre o EcmaScript.next . Às 30:15, ele fala sobre geradores.

Antes, ele explica como a Mozilla está implementando experimentalmente as alterações de idioma propostas para ajudar a dirigir o comitê. Dave trabalha em estreita colaboração com Brendan Eich, CTO da Mozilla (eu acho) e o designer JavaScript original.

Você pode encontrar mais detalhes no wiki do grupo de trabalho EcmaScript: http://wiki.ecmascript.org/doku.php?id=harmony:generators

O grupo de trabalho (TC-39) concorda que o EcmaScript.next deve ter algum tipo de proposta de gerador de iterador, mas isso não é final.

Você não deve confiar nisso aparecendo sem alterações na próxima versão do idioma e, mesmo que não mude, provavelmente não aparecerá amplamente em outros navegadores por um tempo.

Visão geral

Corotinas de primeira classe, representadas como objetos que encapsulam contextos de execução suspensos (ou seja, ativações de funções). Técnica anterior: Python, Ícone, Lua, Esquema, Smalltalk.

Exemplos

A sequência "infinita" de números de Fibonacci (apesar do comportamento em torno de 2 53 ):

function* fibonacci() {
    let [prev, curr] = [0, 1];
    for (;;) {
        [prev, curr] = [curr, prev + curr];
        yield curr;
    }
}

Os geradores podem ser iterados em loops:

for (n of fibonacci()) {
    // truncate the sequence at 1000
    if (n > 1000)
        break;
    print(n);
}

Geradores são iteradores:

let seq = fibonacci();
print(seq.next()); // 1
print(seq.next()); // 2
print(seq.next()); // 3
print(seq.next()); // 5
print(seq.next()); // 8
Mike Samuel
fonte
7
Acompanhamento: o que faz um loop for sem parâmetros ( for(;;))? Por que usá-lo neste contexto?
Fergie
13
@ Bergie, for(;;)é o mesmo que while (true). É usada neste contexto, pois a sequência de Fibonacci é uma sequência ilimitada.
Mike Samuel
5
Técnica anterior: C # yield?
Dave Van den Eynde
3
@DaveVandenEynde, arte anterior anterior: Python yield. Técnica anterior anterior: CLU e Icon.
Mike Samuel
52

É uma função geradora - e foi o que você disse na página que você mencionou, no comentário que você substituiu por "esta é a linha interessante" ...

Basicamente, é uma maneira de especificar seqüências programaticamente para que elas possam ser passadas e elementos acessados ​​pelo índice sem precisar calcular a sequência inteira (possivelmente com tamanho infinito) antecipadamente.

Michael Borgwardt
fonte
10
"acessado por índice sem precisar calcular a sequência inteira" é possivelmente a explicação mais útil sobre geradores que encontrei até agora. Eu pude ver usando isso em um aplicativo, vs anteriormente apenas entendendo isso teoricamente.
wes
11

O function*tipo parece atuar como uma função geradora de processos que podem ser iterados. C # tem um recurso como este usando "yield return", veja 1 e veja 2

Essencialmente, isso retorna cada valor um por um para o que estiver iterando essa função, razão pela qual o caso de uso o mostra em um loop de estilo foreach.

sintaxe inválida
fonte