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)) {
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
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}'`)
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)
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)
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)
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'
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'
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, ) => {
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)
▍ 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)
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)
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)
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)
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)
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)
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)
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)
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'))
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'))
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('ελληνικά'))
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)
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)
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'))
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.
