Guia do JavaScript Parte 9: Visão geral dos padrões ES7, ES8 e ES9

Hoje, na nona parte da tradução do manual JavaScript, será apresentada uma visão geral dos recursos que apareceram no idioma, graças aos padrões ES7, ES8 e ES9.

Parte 1: primeiro programa, recursos de linguagem, padrões
Parte 2: estilo do código e estrutura do programa
Parte 3: variáveis, tipos de dados, expressões, objetos
Parte 4: recursos
Parte 5: matrizes e loops
Parte 6: exceções, ponto e vírgula, literais curinga
Parte 7: modo estrito, esta palavra-chave, eventos, módulos, cálculos matemáticos
Parte 8: Visão geral dos recursos do ES6
Parte 9: Visão geral dos padrões ES7, ES8 e ES9



Padrão ES7


O padrão ES7, que, de acordo com a terminologia oficial, é chamado ES2016, foi lançado no verão de 2016. Ele, em comparação com o ES6, trazido para o idioma não é muito novo. Em particular, estamos falando sobre o seguinte:

  • Array.prototype.includes() .
  • Operador de exponenciação.

▍ Método Array.prototype.includes ()


O método Array.prototype.includes() foi projetado para verificar a presença de um elemento na matriz. Encontrando o desejado na matriz, ele retorna true , não encontrando - false . Antes do ES7, o método indexOf() era usado para executar a mesma operação, que retorna, se um elemento for encontrado, o primeiro índice pelo qual ele pode ser encontrado na matriz. Se indexOf() não encontrar o elemento, ele retornará o número -1 .

De acordo com as regras de conversão do tipo JavaScript, o número -1 convertido em true . Como resultado, para verificar os resultados da operação de indexOf() deve-se usar uma construção não particularmente conveniente do seguinte formulário.

 if ([1,2].indexOf(3) === -1) { console.log('Not found') } 

Se em uma situação semelhante, supondo que indexOf() , sem encontrar um elemento, retorne false , use algo como o mostrado abaixo, o código não funcionará corretamente.

 if (![1,2].indexOf(3)) { // console.log('Not found') } 

Nesse caso, verifica-se que a construção ![1,2].indexOf(3) fornece false .

Usando o método includes() , essas comparações parecem muito mais lógicas.

 if (![1,2].includes(3)) { console.log('Not found') } 

Nesse caso, a construção [1,2].includes(3) retorna false , esse valor é um operador ! vira true e o console recebe uma mensagem informando que o item na matriz não foi encontrado.

Operator operador de exponenciação


O operador de exponenciação executa a mesma função que o método Math.pow() , mas é mais conveniente usá-lo do que uma função de biblioteca, pois faz parte do idioma.

 Math.pow(4, 2) == 4 ** 2 //true 

Esse operador pode ser considerado uma adição agradável ao JS, o que é útil em aplicativos que realizam determinados cálculos. Um operador semelhante existe em outras linguagens de programação.

Padrão ES8


O ES8 Standard (ES2017) foi lançado em 2017. Ele, como o ES7, não trouxe muito ao idioma. Ou seja, estamos falando sobre os seguintes recursos:

  • Adicionando strings a um determinado comprimento.
  • Método Object.values() .
  • Método Object.entries() .
  • Método Object.getOwnPropertyDescriptors() .
  • Vírgulas à direita nos parâmetros de função.
  • Funções assíncronas.
  • Trabalhe com memória compartilhada e operações atômicas.

LinesAdicionando linhas a um determinado comprimento


O ES8 introduziu dois novos métodos de objeto String - padStart() e padEnd() .

O método padStart() preenche a linha atual com outra linha até que a linha final atinja o comprimento desejado. O preenchimento ocorre no início da linha (esquerda). Veja como usar esse método.

 str.padStart(targetLength [, padString]) 

Aqui str é a linha atual, targetLength é o comprimento da linha final (se for menor que o comprimento da linha atual, essa linha será retornada sem alterações), padString é um parâmetro opcional - a linha usada para preencher a linha atual. Se padString não padString especificado, um caractere de espaço será usado para padString linha atual no comprimento especificado.

O método padEnd() é semelhante ao padStart() , mas a linha é preenchida à direita.

Considere exemplos de uso desses métodos.

 const str = 'test'.padStart(10) const str1 = 'test'.padEnd(10,'*') console.log(`'${str}'`) //'      test' console.log(`'${str1}'`) //'test******' 

Aqui, ao usar padStart() apenas com o comprimento desejado da cadeia resultante, foram adicionados espaços ao início da cadeia original. Ao usar padEnd() com o comprimento da linha final e da linha para preenchê-la, os caracteres * foram adicionados ao final da linha original.

▍ Método Object.values ​​()


Este método retorna uma matriz que contém os valores das próprias propriedades do objeto, ou seja, aquelas que o objeto contém e não aquelas que são acessíveis a ele através da cadeia de protótipos.

Veja como usá-lo.

 const person = { name: 'Fred', age: 87 } const personValues = Object.values(person) console.log(personValues) // ['Fred', 87] 

Este método também se aplica a matrizes.

▍ Método Object.entries ()


Este método retorna uma matriz, cada elemento da qual também é uma matriz que contém, no formato [key, value] , chaves e valores das próprias propriedades do objeto.

 const person = { name: 'Fred', age: 87 } const personValues = Object.entries(person) console.log(personValues) // [['name', 'Fred'], ['age', 87]] 

Ao aplicar esse método a matrizes, os índices dos elementos são exibidos como chaves e o que é armazenado na matriz nos índices correspondentes é exibido como valores.

▍ método getOwnPropertyDescriptors ()


Este método retorna informações sobre todas as propriedades do próprio objeto. Os conjuntos de atributos (descritores) estão associados às propriedades do objeto. Em particular, estamos falando dos seguintes atributos:

  • value - o valor da propriedade do objeto.
  • writable - contém true se a propriedade puder ser alterada.
  • get - contém uma função getter associada à propriedade ou, se não houver essa função, undefined .
  • set - contém a função setter para a propriedade ou undefined .
  • configurable - se for false - a propriedade não pode ser excluída, seus atributos não podem ser alterados, exceto pelo valor.
  • enumerable - se true estiver contido nessa propriedade - a é enumerável.

Veja como usar esse método.

 Object.getOwnPropertyDescriptors(obj) 

Ele pega um objeto cujas informações de propriedade você precisa descobrir e retorna um objeto que contém essas informações.

 const person = { name: 'Fred', age: 87 } const propDescr = Object.getOwnPropertyDescriptors(person) console.log(propDescr) /* { name:  { value: 'Fred',    writable: true,    enumerable: true,    configurable: true }, age:  { value: 87,    writable: true,    enumerable: true,    configurable: true } } */ 

Por que esse método é necessário? O fato é que ele permite criar cópias pequenas de objetos, copiando, além de outras propriedades, getters e setters. Isso não pôde ser feito usando o método Object.assign() , que apareceu no padrão ES6, para copiar objetos.

O exemplo a seguir possui um objeto com um setter que exibe, usando console.log() , o que eles estão tentando gravar em sua propriedade correspondente.

 const person1 = { set name(newName) {     console.log(newName) } } person1.name = 'x' // x 

Vamos tentar copiar esse objeto usando o método assign() .

 const person2 = {} Object.assign(person2, person1) person2.name = 'x' //     ,    

Como você pode ver, essa abordagem não funciona. A propriedade name , que era o setter no objeto original, agora é representada como uma propriedade regular.

Agora, copiaremos o objeto usando os métodos Object.defineProperties() (que apareceu no ES5.1) e Object.getOwnPropertyDescriptors() .

 const person3 = {} Object.defineProperties(person3, Object.getOwnPropertyDescriptors(person1)) person3.name = 'x' //x 

Aqui, o setter permanece na cópia do objeto.

Deve-se notar que as restrições específicas ao Object.assign() também são características do método Object.create() quando usado para clonar objetos.

Vírgulas de conclusão nos parâmetros de função


Esse recurso permite deixar uma vírgula no final da lista de parâmetros ou argumentos, respectivamente, ao declarar e ao chamar funções.

 const doSomething = ( var1, var2, ) => { //... } doSomething( 'test1', 'test2', ) 

Isso melhora a usabilidade dos sistemas de controle de versão. Ou seja, estamos falando sobre o fato de que, ao adicionar novos parâmetros a uma função, você não precisa alterar o código existente apenas para inserir uma vírgula.

▍ Funções assíncronas


A construção async/await aguardada apareceu no padrão ES2017, que pode ser considerada a inovação mais importante desta versão do idioma.

As funções assíncronas são uma combinação de promessas e geradores; elas simplificam construções que anteriormente exigiam uma grande quantidade de código de modelo e cadeias inconvenientes de promessas para descrever. De fato, estamos falando de uma abstração de alto nível sobre promessas.

Quando as promessas apareceram no padrão ES2015, elas foram projetadas para resolver problemas existentes com código assíncrono, o que foram. Porém, ao longo dos dois anos que compartilharam os padrões ES2015 e ES2017, ficou claro que as promessas não podem ser consideradas a solução final para esses problemas.

Em particular, as promessas tinham como objetivo solucionar o problema do "inferno de retorno de chamada", mas, tendo resolvido esse problema, elas mesmas não mostraram seu melhor lado devido à complexidade do código em que são usadas. Por uma questão de fato, a construção async/await resolve o problema das promessas e melhora a usabilidade do código assíncrono.

Considere um exemplo.

 function doSomethingAsync() { return new Promise((resolve) => {     setTimeout(() => resolve('I did something'), 3000) }) } async function doSomething() { console.log(await doSomethingAsync()) } console.log('Before') doSomething() console.log('After') 

Este código produzirá o seguinte para o console.

 Before After I did something 

Como você pode ver, depois de chamar doSomething() programa continua em execução, depois que Before , After é exibido no console e depois de três segundos, I did something .

Chamada de função assíncrona serial


Se necessário, funções assíncronas podem formar algo como cadeias de chamadas. Tais projetos são diferenciados por uma melhor legibilidade do que algo semelhante, baseado apenas em promessas. Isso pode ser visto no exemplo a seguir.

 function promiseToDoSomething() { return new Promise((resolve)=>{     setTimeout(() => resolve('I did something'), 10000) }) } async function watchOverSomeoneDoingSomething() { const something = await promiseToDoSomething() return something + ' and I watched' } async function watchOverSomeoneWatchingSomeoneDoingSomething() { const something = await watchOverSomeoneDoingSomething() return something + ' and I watched as well' } watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => { console.log(res) // I did something and I watched and I watched as well }) 

▍ Memória compartilhada e operações atômicas


Aqui estamos falando sobre o objeto SharedArrayBuffer , que permite descrever áreas de memória compartilhada, e o objeto Atomics , que contém um conjunto de operações atômicas na forma de métodos estáticos. Detalhes sobre as possibilidades que esses objetos oferecem ao programador podem ser encontrados aqui .

Padrão ES9


ES9 (ES2018) é a versão mais recente do padrão no momento da publicação deste material. Aqui estão suas principais características:

  • Aplique instruções de expansão e descanso aos objetos.
  • Iteradores assíncronos.
  • Método Promise.prototype.finally() .
  • Aprimoramentos de expressão regular.

Aplicação de operadores de espalhamento e repouso a objetos


Já falamos sobre os operadores de resto e propagação que apareceram no ES6 e podem ser usados ​​para trabalhar com matrizes. Ambos parecem três pontos. O operador rest, no exemplo a seguir de destruição de uma matriz, permite que você coloque seus primeiro e segundo elementos nas constantes first e second e todo o resto nas constantes constantes.

 const numbers = [1, 2, 3, 4, 5] const [first, second, ...others] = numbers console.log(first) //1 console.log(second) //2 console.log(others) //[ 3, 4, 5 ] 

O operador spread permite passar matrizes para funções que esperam listas de parâmetros regulares.

 const numbers = [1, 2, 3, 4, 5] const sum = (a, b, c, d, e) => a + b + c + d + e const res = sum(...numbers) console.log(res) //15 

Agora, usando a mesma abordagem, você pode trabalhar com objetos. Aqui está um exemplo de uso da instrução rest em uma operação de atribuição destrutiva.

 const { first, second, ...others } = { first: 1, second: 2, third: 3, fourth: 4, fifth: 5 } console.log(first) //1 console.log(second) //2 console.log(others) //{ third: 3, fourth: 4, fifth: 5 } 

Aqui está a instrução de dispersão usada ao criar um novo objeto com base em um existente. Este exemplo continua o anterior.

 const items = { first, second, ...others } console.log(items) //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 } 

Iteradores assíncronos


A nova construção for-await-of permite chamar funções assíncronas que retornam promessas em loops. Esses loops aguardam a resolução da promessa antes de passar para o próximo passo. Aqui está como fica.

 for await (const line of readLines(filePath)) { console.log(line) } 

Ao mesmo tempo, deve-se notar que esses loops devem ser usados ​​em funções assíncronas - da mesma maneira que quando se trabalha com a construção async/await .

Method Método Promise.prototype.finally ()


Se a promessa for resolvida com sucesso, o próximo método then() será chamado. Se algo der errado, o método catch() é chamado. O método finally() permite que você execute algum código, independentemente do que aconteceu antes.

 fetch('file.json') .then(data => data.json()) .catch(error => console.error(error)) .finally(() => console.log('finished')) 

▍ Melhorias na expressão regular


Expressões regulares têm a capacidade de verificar retrospectivamente cadeias de caracteres ( ?<= ). Isso permite procurar determinadas construções nas linhas antes das quais existem outras construções.

A capacidade de preceder verificações usando o ?= Construct estava presente em expressões regulares implementadas em JavaScript antes do padrão ES2018. Essas verificações permitem que você saiba se outro fragmento segue um certo fragmento de uma linha.

 const r = /Roger(?= Waters)/ const res1 = r.test('Roger is my dog') const res2 = r.test('Roger is my dog and Roger Waters is a famous musician') console.log(res1) //false console.log(res2) //true 

Construção ?! realiza a operação oposta - uma correspondência será encontrada apenas se outra linha não seguir a linha especificada.

 const r = /Roger(?! Waters)/g const res1 = r.test('Roger is my dog') const res2 = r.test('Roger is my dog and Roger Waters is a famous musician') console.log(res1) //true console.log(res2) //false 

Na verificação retrospectiva, como já mencionado, a construção ?<= usada.

 const r = /(?<=Roger) Waters/ const res1 = r.test('Pink Waters is my dog') const res2 = r.test('Roger is my dog and Roger Waters is a famous musician') console.log(res1) //false console.log(res2) //true 

A operação oposta à descrita pode ser realizada usando a construção ?<! .

 const r = /(?<!Roger) Waters/ const res1 = r.test('Pink Waters is my dog') const res2 = r.test('Roger is my dog and Roger Waters is a famous musician') console.log(res1) //true console.log(res2) //false 

Sequências de escape de regex Unicode


Em expressões regulares, você pode usar a classe \d que corresponde a qualquer dígito, a classe \s que corresponde a qualquer caractere de espaço em branco, a classe \w que corresponde a qualquer caractere alfanumérico e assim por diante. O recurso em questão estende o conjunto de classes que podem ser usadas em expressões regulares, permitindo trabalhar com sequências Unicode. Estamos falando da classe \p{} e do inverso da classe \P{} .

No Unicode, cada caractere possui um conjunto de propriedades. Essas propriedades são indicadas entre chaves do grupo \p{} . Assim, por exemplo, a propriedade Script determina a família de idiomas à qual um caractere pertence, a propriedade ASCII , lógica, é true para caracteres ASCII e assim por diante. Por exemplo, descobriremos se algumas linhas contêm apenas caracteres ASCII.

 console.log(r.test('abc')) //true console.log(r.test('ABC@')) //true console.log(r.test('ABC')) //false 

A propriedade ASCII_Hex_Digit é true apenas para caracteres que podem ser usados ​​para gravar números hexadecimais.

 const r = /^\p{ASCII_Hex_Digit}+$/u console.log(r.test('0123456789ABCDEF')) //true console.log(r.test('H')) //false 

Existem muitas outras propriedades semelhantes usadas da mesma maneira descrita acima. Entre eles estão Uppercase , Lowercase , White_Space , Alphabetic , Emoji .

Por exemplo, veja como usar a propriedade Script para determinar qual alfabeto é usado em uma sequência. Aqui, verificamos a string para uso do alfabeto grego.

 const r = /^\p{Script=Greek}+$/u console.log(r.test('ελληνικά')) //true console.log(r.test('hey')) //false 

Detalhes sobre essas propriedades podem ser encontrados aqui .

Grupos Nomeados


Grupos de caracteres capturados no ES2018 podem receber nomes. Aqui está como fica.

 const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ const result = re.exec('2015-01-02') console.log(result) /* [ '2015-01-02', '2015', '01', '02', index: 0, input: '2015-01-02', groups: { year: '2015', month: '01', day: '02' } ] */ 

Sem o uso de grupos nomeados, os mesmos dados estariam disponíveis apenas como elementos de matriz.

 const re = /(\d{4})-(\d{2})-(\d{2})/ const result = re.exec('2015-01-02') console.log(result) /* [ '2015-01-02', '2015', '01', '02', index: 0, input: '2015-01-02', groups: undefined ] */ 

Bandeira regex s


Usar a bandeira s resulta em um caractere . (ponto) corresponderá, entre outros, ao caractere de nova linha. Sem esse sinalizador, um ponto corresponde a qualquer caractere, exceto por uma nova linha.

 console.log(/hi.welcome/.test('hi\nwelcome')) // false console.log(/hi.welcome/s.test('hi\nwelcome')) // true 

Sumário


Com este material, estamos concluindo a publicação das traduções deste manual JavaScript. Esperamos que essas publicações tenham ajudado aqueles que não tinham trabalhado com JavaScript antes a dar os primeiros passos na programação nessa linguagem.

Caros leitores! Se você ainda não escreveu em JS e dominou esse idioma neste guia, compartilhe suas impressões.

Source: https://habr.com/ru/post/pt431872/


All Articles