É… foo um operador ou syntax?

Já ouvi falar de “spread syntax ” e “the spread operator “, com o último sendo muito mais popular. A URL da documentação relevante do MDN sugere que ela foi inicialmente referida como o operador de propagação , mas posteriormente alterada para syntax de propagação, e a lista de operadores do MDN não a menciona.

O Google parece sugerir que o termo operador é mais popular e aceito, com sites como a documentação da Microsoft e es6-features.org se referindo a ele como tal.

Qual termo seria o mais correto no contexto do ECMAScript, se algum, e por quê? E quanto à atribuição de desestruturação de array?

Não é um operador.

Em todos os sentidos da palavra, não é um. Tem sido um equívoco enorme desde que foi introduzido e apesar da opinião popular – não é um, e há alguns pontos objectives a serem feitos:

  • Não se encheckbox na definição de um operador
  • Não pode ser usado como um operador
  • A especificação da linguagem implica que não é um operador

Deve-se mencionar que a syntax de propagação vem em diferentes ‘sabores’, usada em diferentes contextos e é comumente referida por nomes diferentes enquanto usa o mesmo pontuador. A syntax de propagação é basicamente um termo geral para a aplicação do ... pontuador, e vê a grande resposta de Felix Kling detalhando todos os usos e nomes. Mais explicações sobre esses usos individuais são dadas na resposta suplementar .

O que é um operador?

Semanticamente, no contexto do ECMAScript, os operadores são apenas funções embutidas que recebem argumentos e avaliam um único valor – escrito em prefixo, infixo ou notação postfix e geralmente com nomes simbólicos como + ou / . Da Wikipedia :

Simplesmente, uma expressão envolvendo um operador é avaliada de alguma forma, e o valor resultante pode ser apenas um valor (um valor-r), ou pode ser um object que permita a atribuição (um valor-l).

Por exemplo, o operador + resulta em um valor como 2, que é uma expressão do lado direito, e o . O operador resulta em um object que permite atribuição, como foo.bar , uma expressão do lado esquerdo.

Na superfície, o ... pontuador 1 parece ser um operador unário de prefixo:

 const baz = [foo, ...bar]; 

Mas o problema com esse argumento é que ...bar não avalia um valor singular; Ele espalha os elementos da bar iterável, um por um. O mesmo vale para argumentos de propagação:

 foo(...bar); 

Aqui, foo recebe argumentos separados da bar iterável. Eles são valores separados sendo passados ​​para foo , não apenas um valor. Não se encheckbox na definição de um operador, então não é um.

Por que não é um operador?

Outro ponto a ser feito é que os operadores devem ser independentes e retornar um único valor. Por exemplo:

 const bar = [...foo]; 

Como já mencionado, isso funciona bem. O problema surge quando você tenta fazer isso:

 const bar = ...foo; 

Se a syntax de propagação fosse um operador, o último funcionaria bem, porque os operadores avaliam a expressão para um único valor, mas a propagação não falha. A syntax de propagação e os argumentos de propagação funcionam somente no contexto de matrizes e chamadas de function, porque essas estruturas recebem vários valores fornecidos pelos elementos ou argumentos de matriz de dispersão. Avaliar para vários valores está fora do escopo do que um operador é capaz de fazer.

O que dizem os padrões?

A lista completa de operadores está listada nas Cláusulas §12.5 a §12.15 na especificação de linguagem ECMAScript 2015 , a especificação na qual ... é introduzida, que não menciona ... Também pode ser inferido que não é um operador. Os dois casos principais mencionados nesta resposta, nos quais a syntax de propagação está em uma produção, para chamadas de function (argumentos de propagação) ou literais de matriz (syntax de propagação) são descritos abaixo:

  ArrayLiteral:
   [Elision opt ]
   [ElementList]
   [ElementList, Elisionopt]

 ElementList:
   Elision opt AssignmentExpression
   Elision opt SpreadElement
   ElementList, Elision opt AssignmentExpression
   ElementList, Elision opt SpreadElement

 Elision:
   ,
   Elision,

 SpreadElement:
   ... AssignmentExpression
  

E para chamadas de function :

  CallExpression:
   Argumentos MemberExpression

 Argumentos:
   ()
   (ArgumentList)

 ArgumentList:
   AssignmentExpression
   ... AssignmentExpression
   ArgumentList, AssignmentExpression
   ArgumentList, ... AssignmentExpression
  

Nessas produções, há uma conclusão que pode ser feita: que o spread ‘operator’ não existe. Como mencionado anteriormente, os operadores devem ser independentes, como em const bar = ...foo e avaliar para um único valor. A syntax da linguagem impede isso, o que significa que a syntax de propagação nunca foi feita para ser independente. É uma extensão para inicializar matrizes e chamadas de function , uma extensão para sua gramática.

Por que espalhar “syntax”?

Sintaxe, conforme definido pela Wikipedia :

Na ciência da computação, a syntax de uma linguagem de computador é o conjunto de regras que define as combinações de símbolos que são considerados um documento ou fragment estruturado corretamente nesse idioma.

A syntax é basicamente a “forma” da linguagem, regras que governam o que é legal ou não a respeito de como o código deve parecer e como o código deve ser escrito. Nesse caso, a gramática do ECMAScript define especificamente o ... pontuador para aparecer apenas em chamadas de function e literais de matriz como uma extensão – que é uma regra que define uma combinação de símbolos ( ...foo ) considerados legais juntos , portanto, é syntax semelhante a como uma function de seta ( => ) não é um operador, mas uma syntax 2 .

Chamando ... um operador é um equívoco. Um operador é uma function incorporada que aceita argumentos (operandos) e está na forma de notação de prefixo, infixo ou pós-correção e avalia exatamente um valor . ... , enquanto satisfaz as duas primeiras condições, não satisfaz o último. ... , em vez disso, é a syntax porque é definida especificamente e explicitamente na gramática da linguagem. Assim, “o operador de spread” é ​​objetivamente mais corretamente chamado de “syntax de spread”.


1 O termo ‘pontuador’ refere-se a pontuadores no ECMAScript 2015 e especificações posteriores. Esses símbolos incluem componentes e operadores de syntax e são pontuadores da linguagem. ... é um pontuador em si, mas o termo “syntax de propagação” refere-se à aplicação inteira do pontuador.

2 => si é um pontuador , assim como ... mas o que estou me referindo especificamente é a syntax da function de seta , a aplicação do => pontuador ( (…) => { … } ), assim como a syntax de propagação se refere a a aplicação do ... pontuador.

Outros usos da syntax

Existem outros usos numerosos da syntax spread / rest não cobertos na resposta principal. Eles incluem:

  • Rest syntax em parâmetros de function
  • Atribuição de desdobramento de matriz e object 1
  • Sintaxe de propagação de object em literais de object 1

Sintaxe Rest

Um uso para a syntax de propagação, comumente referido como syntax rest , é usado para um número variável de argumentos nos argumentos de uma function. Isso difere dos argumentos de propagação, usados ​​para transmitir argumentos para uma chamada de function com base nos elementos de um iterável. Por exemplo:

 function add(...addends) { … } 

Aqui, a syntax rest é usada para a function add para receber o restante dos argumentos nos addends do identificador. Isso parece avaliar para um valor singular como addends é uma matriz dos argumentos passados, mas e se nós tentamos:

 function foo(...[bar, baz]) { … } 

Aqui, bar e baz seriam atribuídos a ambos um valor correspondente ao primeiro e segundo argumentos passados ​​- portanto, isso nem sempre avalia um valor. O problema subjacente é que ...addends no primeiro exemplo e ...[bar, baz] no segundo, na verdade, não avaliam um valor – é usado apenas durante a operação de designar uma matriz de argumentos para o identificador. Assim, é a syntax para permitir um número variável de argumentos para uma function, não um operador.

Atribuição de Destruturação

A syntax de propagação também pode ser usada durante a atribuição de desestruturação de matriz e é, na verdade, referida como um elemento de descanso na especificação da linguagem (porque ao usar na desestruturação, ela fica com o restante do desestruturado iterável). Um argumento convincente pode ser feito, pois isso parece um operador:

 const [...bar] = [1, 2, 3]; 

É usado como um operador unário de prefixo. Aqui, bar avalia para [1, 2, 3] – que é um valor único. Mas isso nem sempre acontece, por exemplo:

 const [first, ...[second, third]] = [1, 2, 3]; 

Aqui, first , second e third avaliam para 1, 2 e 3, respectivamente. Mas ...[second, third] atribui dois identificadores, não um, e não avalia um valor singular, mas dois. Assim como a syntax do descanso, o problema subjacente é que ...bar no primeiro exemplo e ...[second, third] no segundo , na verdade, não é avaliado em um valor – é usado apenas durante a operação de atribuição . Assim, não é um operador 2 , apenas uma nova syntax para ajudar a descompactar os valores.

Sintaxe de propagação de object

Um uso final para a syntax de propagação está nos literais de object, comumente chamados de ‘propriedades de propagação de object’, nas quais as propriedades enumeráveis ​​do próprio object de destino são espalhadas para outro, por exemplo:

 const foo = { ...bar }; 

Este não é um operador, assim como a syntax de propagação de array não é um operador. O conceito é o mesmo, em vez de índices e elementos em arrays, as chaves e valores enumeráveis ​​da bar são espalhados para foo . Aqui, uma coleção de propriedades da bar é distribuída – não apenas um único valor, portanto, não se encheckbox na definição de um operador.


1 As propriedades de repouso / propagação de objects estão atualmente na proposta do Estágio 3 para o ECMAScript, e muito provavelmente serão adicionadas em breve

2 Outro problema com a atribuição de desestruturação sendo um operador, além da semântica, é que a especificação da linguagem a define como syntax suplementar – não um operador suplementar , e com razão. Não é autônomo, pois isso não funcionará:

 const ...bar = [1, 2, 3, 4]; 

É contextual, permitido apenas, pela gramática da linguagem, literais de object e literais de array que são expressões do lado esquerdo. Também é a gramática que refina a interpretação de uma expressão do lado esquerdo . Mais uma vez, esta é uma extensão para adicionar nova syntax à linguagem, um refinamento da gramática existente. Isso reafirma o argumento com especificação.