O material, a primeira parte da tradução que estamos publicando hoje, é dedicado aos novos recursos JavaScript padrão que foram discutidos na conferência
Google I / O 2019 . Em particular, aqui falaremos sobre expressões regulares, sobre campos de classe, sobre como trabalhar com strings.

Verificações de expressão regular
Expressões regulares (Expressão Regular, para abreviação - RegEx ou RegExp) é uma poderosa tecnologia de processamento de strings implementada em muitas linguagens de programação. Expressões regulares são muito úteis nos casos em que você precisa, por exemplo, procurar fragmentos de cadeias por padrões complexos. Até recentemente, a implementação de JavaScript de expressões regulares tinha tudo, menos olhar para trás.
Para entender o que é uma verificação retrospectiva, primeiro vamos falar sobre os cabeçotes de impressão que já são compatíveis com JavaScript.
→
A segunda parteCheck Verificação prévia
A sintaxe das verificações iniciais em expressões regulares permite procurar fragmentos de seqüências de caracteres quando se sabe que outros fragmentos estão à direita deles. Por exemplo, ao trabalhar com as seqüências
MangoJuice, VanillaShake, GrapeJuice
você pode usar a sintaxe da verificação inicial positiva para encontrar as palavras imediatamente seguidas pela palavra
Juice
. No nosso caso, essas são as palavras
Mango
e
Grape
.
Existem dois tipos de verificações iniciais. Essas são visões positivas e negativas.
Verificação positiva de chumbo
Uma verificação inicial positiva é usada para procurar linhas à direita das quais são outras linhas anteriormente conhecidas. Veja como é a sintaxe da expressão regular usada para esta verificação:
/[a-zA-Z]+(?=Juice)/
Este modelo permite selecionar palavras que consistem em letras minúsculas ou maiúsculas, seguidas pela palavra
Juice
. Não confunda estruturas que descrevem verificações iniciais e retrospectivas com grupos de captura. Embora as condições dessas verificações sejam escritas entre parênteses, o sistema não as captura. Vejamos um exemplo de uma verificação de lead positiva.
const testString = "MangoJuice, VanillaShake, GrapeJuice"; const testRegExp = /[a-zA-Z]+(?=Juice)/g; const matches = testString.match( testRegExp ); console.log( matches );
Verificação negativa de lead
Se considerarmos, usando a linha acima, o mecanismo de ação dos cheques iniciais negativos, verifica-se que eles permitem que você encontre palavras à direita das quais não há palavra
Juice
. A sintaxe das verificações iniciais negativas é semelhante à sintaxe das verificações positivas. No entanto, existe uma característica: o símbolo
=
(igual) muda para um símbolo
!
(ponto de exclamação). Aqui está o que parece:
/[a-zA-Z]+(?!Juice)/
Essa expressão regular permite selecionar todas as palavras à direita das quais não há palavra
Juice
. Porém, ao aplicar esse modelo, todas as palavras da linha serão selecionadas (
MangoJuice, VanillaShake, GrapeJuice
). O fato é que, de acordo com o sistema, nenhuma palavra aqui termina com
Juice
. Como resultado, para alcançar o resultado desejado, é necessário esclarecer a expressão regular e reescrevê-la da seguinte maneira:
/(Mango|Vanilla|Grape)(?!Juice)/
O uso desse modelo permite selecionar as palavras
Mango
,
Vanilla
ou
Grape
, após as quais não há palavra
Juice
. Aqui está um exemplo:
const testString = "MangoJuice, VanillaShake, GrapeJuice"; const testRegExp = /(Mango|Vanilla|Grape)(?!Juice)/g; const matches = testString.match( testRegExp ); console.log( matches );
Check Verificação Retrospectiva
Por analogia com a sintaxe das verificações iniciais, a sintaxe das verificações retrospectivas permite selecionar seqüências de caracteres apenas se à esquerda dessas seqüências houver um determinado padrão especificado. Por exemplo, ao processar a sequência
FrozenBananas, DriedApples, FrozenFish
podemos usar uma verificação retrospectiva positiva para encontrar palavras à esquerda das quais existe a palavra
Frozen
. No nosso caso, as palavras
Bananas
e
Fish
correspondem a essa condição.
Existem, como é o caso das verificações iniciais, verificações retrospectivas positivas (olhar positivo para trás) e verificações retrospectivas negativas (olhar negativo ou negativo).
Revisão retrospectiva positiva
Verificações retrospectivas positivas são usadas para procurar padrões à esquerda dos quais existem outros padrões. Aqui está um exemplo da sintaxe usada para descrever essas verificações:
/(?<=Frozen)[a-zA-Z]+/
O símbolo
<
usado aqui, que não estava na descrição das verificações iniciais. Além disso, a condição na expressão regular está localizada não à direita do modelo de interesse para nós, mas à esquerda. Usando o modelo acima, você pode selecionar todas as palavras que começam com
Frozen
. Considere um exemplo:
const testString = "FrozenBananas, DriedApples, FrozenFish"; const testRegExp = /(?<=Frozen)[a-zA-Z]+/g; const matches = testString.match( testRegExp ); console.log( matches );
Verificação retrospectiva negativa
O mecanismo de verificações retrospectivas negativas permite procurar padrões nas linhas à esquerda das quais não há um padrão especificado. Por exemplo, se você precisar selecionar palavras que não iniciam com
Frozen
na linha
FrozenBananas, DriedApples, FrozenFish
, tente usar esta expressão regular:
/(?<!Frozen)[a-zA-Z]+/
Mas, como usar essa construção levará à seleção de todas as palavras da string, uma vez que nenhuma delas começa com
Frozen
, a expressão regular precisa ser esclarecida:
/(?<!Frozen)(Bananas|Apples|Fish)/
Aqui está um exemplo:
const testString = "FrozenBananas, DriedApples, FrozenFish"; const testRegExp = /(?<!Frozen)(Bananas|Apples|Fish)/g; const matches = testString.match( testRegExp ); console.log( matches );
→ Suporte
Esta e outras seções semelhantes fornecerão informações sobre o estágio de harmonização dos recursos JS descritos no Comitê Técnico 39 (Comitê Técnico 39, TC39), responsável pela ECMA International pelo suporte às especificações do ECMAScript. Essas seções também fornecerão dados sobre as versões do Chrome e do Node.js (e algumas vezes sobre a versão do Firefox), começando com as quais você pode usar os recursos correspondentes.
Campos de classe
Um campo de classe é uma nova construção de sintaxe usada para definir as propriedades de instâncias de classe (objetos) fora do construtor de classe. Existem dois tipos de campos de classe: campos de classe pública e privada.
Campos de classe pública
Até recentemente, as propriedades dos objetos tinham que ser definidas dentro do construtor da classe. Essas propriedades eram públicas (públicas). Isso significa que eles podem ser acessados trabalhando com uma instância da classe (objeto). Aqui está um exemplo de declarar uma propriedade pública:
class Dog { constructor() { this.name = 'Tommy'; } }
Quando era necessário criar uma classe que estendesse uma certa classe pai, era necessário chamar
super()
no construtor da classe filho. Isso precisava ser feito antes que suas próprias propriedades pudessem ser adicionadas à classe filho. Aqui está o que parece:
class Animal {} class Dog extends Animal { constructor() { super();
Graças à aparência da sintaxe dos campos públicos de uma classe, é possível descrever os campos de classe fora do construtor. O sistema fará uma chamada implícita para
super()
.
class Animal {} class Dog extends Animal { sound = 'Woof! Woof!';
Ao chamar implicitamente
super()
ele passa todos os argumentos fornecidos pelo usuário ao criar a instância da classe (esse é o comportamento padrão do JavaScript, não há nada de especial nos campos da classe privada). Se o construtor da classe pai precisar de argumentos preparados de uma maneira especial, você precisará chamar
super()
. Dê uma olhada nos resultados da chamada implícita do construtor da classe pai ao criar uma instância da classe filho.
class Animal { constructor( ...args ) { console.log( 'Animal args:', args ); } } class Dog extends Animal { sound = 'Woof! Woof!';
Fields Campos de classe privada
Como você sabe, em JavaScript, não há modificadores de acesso aos campos de classe, como
public
,
private
ou
protected
. Todas as propriedades dos objetos são públicas por padrão. Isso significa que o acesso a eles é ilimitado. O mais próximo de tornar uma propriedade de um objeto semelhante a uma propriedade privada é usar o tipo de dados
Symbol
. Isso permite ocultar as propriedades dos objetos do mundo exterior. Você pode ter usado nomes de propriedades prefixados com
_
(sublinhado) para indicar que as propriedades correspondentes devem ser consideradas apenas destinadas ao uso no objeto. No entanto, esse é apenas um tipo de notificação para quem usará a instalação. Isso não resolve o problema de restrição real do acesso às propriedades.
Graças ao mecanismo de campos particulares de classes, é possível tornar as propriedades da classe acessíveis somente dentro desta classe. Isso leva ao fato de que eles não podem ser acessados de fora e trabalhar com uma instância da classe (objeto). Pegue o exemplo anterior e tente acessar a propriedade da classe de fora, quando o prefixo
_
foi usado.
class Dog { _sound = 'Woof! Woof!';
Como você pode ver, o uso do prefixo
_
não resolve nosso problema. Os campos privados das classes podem ser declarados da mesma maneira que os campos públicos, mas, em vez de um prefixo na forma de sublinhado, você deve adicionar um prefixo na forma de um sinal de cerquilha (
#
) a seus nomes. Uma tentativa de acesso não autorizado à propriedade privada do objeto declarada dessa maneira resultará no seguinte erro:
SyntaxError: Undefined private field
Aqui está um exemplo:
class Dog { #sound = 'Woof! Woof!';
Observe que propriedades privadas podem ser acessadas apenas a partir da classe em que são declaradas. Como resultado, as classes descendentes não podem usar diretamente propriedades semelhantes da classe pai.
Campos privados (e públicos) podem ser declarados sem escrever determinados valores neles:
class Dog { #name; constructor( name ) { this.#name = name; } showName() { console.log( this.#name ); } }
→ Suporte
- TC39: Etapa 3
- Chrome: mais de 74
- Nó: 12+
Método de string .matchAll ()
O protótipo de tipo de dados
String
possui um método
.match()
que retorna uma matriz de fragmentos de string que correspondem à condição especificada pela expressão regular. Aqui está um exemplo usando este método:
const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /([A-Z0-9]+)/g; console.log( colors.match( matchColorRegExp ) );
Ao usar esse método, no entanto, nenhuma informação adicional é fornecida (como índices) sobre os fragmentos encontrados da string. Se você remover o sinalizador
g
da expressão regular passada para o método
.match()
, ele retornará uma matriz que conterá informações adicionais sobre os resultados da pesquisa. No entanto, com essa abordagem, apenas o primeiro fragmento da string correspondente à expressão regular será encontrado.
const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/; console.log( colors.match( matchColorRegExp ) );
Para obter algo semelhante, mas para vários fragmentos de uma string, você precisará usar o método de expressão regular
.exec()
. As construções necessárias para isso são mais complicadas do que aquela em que um método de cadeia única seria usado para obter resultados semelhantes. Em particular, aqui precisamos de um
while
que será executado até que
.exec()
retorne
null
. Usando essa abordagem, lembre-se de que
.exec()
não retorna um iterador.
const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/g;
Para resolver esses problemas, agora podemos usar o método string
.matchAll()
, que retorna um iterador. Cada chamada para o método
.next()
deste iterador
.next()
próximo elemento dos resultados da pesquisa. Como resultado, o exemplo acima pode ser reescrito da seguinte maneira:
const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/g; console.log( ...colors.matchAll( matchColorRegExp ) );
→ Suporte
Grupos nomeados em expressões regulares
O conceito de grupos na implementação de JavaScript de mecanismos de expressão regular é um pouco diferente da implementação de um conceito semelhante em outros idiomas. Ou seja, quando, usando JavaScript, o modelo RegEx é colocado entre parênteses (exceto quando parênteses são usados para verificações retrospectivas ou avançadas), o modelo se torna um grupo.
Os fragmentos da sequência capturada pelo grupo serão refletidos nos resultados da aplicação da expressão regular.
No exemplo anterior, você pode ver que o primeiro elemento da matriz com os resultados da pesquisa é o que corresponde a toda a expressão regular e o segundo é o que corresponde ao grupo. Aqui está este elemento do array:
["#EEE", "EEE", index: 0, input: "<colors>"]
Se houver vários grupos na expressão regular, eles entrarão nos resultados do processamento da sequência na ordem de sua descrição na expressão regular. Considere um exemplo:
const str = "My name is John Doe."; const matchRegExp = /My name is ([az]+) ([az]+)/i; const result = str.match( matchRegExp );console.log( result );
Aqui você pode ver que a primeira linha da saída é a linha inteira correspondente à expressão regular. O segundo e o terceiro elementos representam o que foi capturado pelos grupos.
O uso de grupos nomeados permite salvar quais grupos estão capturando no objeto de
groups
, cujos nomes de propriedades correspondem aos nomes atribuídos aos grupos.
const str = "My name is John Doe."; const matchRegExp = /My name is (?<firstName>[az]+) (?<lastName>[az]+)/i; const result = str.match( matchRegExp ); console.log( result ); console.log( result.groups );
Note-se que os grupos nomeados funcionam bem junto com o método
.matchAll()
.
→ Suporte
- TC39: Etapa 4
- Chrome: mais de 64
- Nó: 10+
Para continuar ...
Caros leitores! Você já usou alguma das inovações em JavaScript descritas aqui?
