- Published on
EcmaScript (Javascript and NodeJS) - Whats New from ES7 to ES10
Quick note: work in progress on this translation
Bora Lembrar das Novidades do ES7+
Você que usa JS no dia a dia, ou até de vez em quando já parou pra pensar nas atualizações que vieram depois do ES6? E as que vão vir?
Pra falar a verdade eu não, aí resolvi procurar e escrever, assim memorizo mais fácil, esse é meu jeito de "aprender". Então se você tá lendo, vamo junto tentar entender alguma coisa do Javascript, desde o ES7 até o ES10, daí eu não esqueço, e se eu falar besteira você me avisa, pode ser?! ES10?
Sim já chegamos no ES10, então fica esperto que logo logo o JS tá correndo mais que o Bolt.
Lembrando que não vou citar todas as mudanças ou todas as features, mas vou tentar citar as principais/classicas que já vi usarem, ou que estão "mais faladas".
Bora codar!
ES7
Acho que o mais simples de pegar as atualizações, afinal, as novidades são:
- método "includes" nos Arrays
- método "includes" em Strings
- Operador exponencial "**"
Já usou o includes?! Tinha noção que era "tão recente"?! Pois é…então é isso aí! Flw, é noses!.
Brinks, let's bora codar isso que é bem simples:
O includes() retorna true/false no caso de a string conter ou não o caractere, palavra, frase que você passar. Lembrando que é case-sensitive.
Primeiro exemplo de includes:
//testando o includes() com strings
const frase = 'Hello world'
include = frase.includes('w') //retorna true
console.log(include)
// é case sensitive
include = frase.includes('L') //retorna false
console.log(include)
include = frase.includes('x') //retorna false
console.log(include)
Agora com arrays:
const animais = ['cachorro', 'gato', 'urso']
include = animais.includes('cachorro')
console.log(include) //returna true
include = animais.includes('eu')
console.log(include) //returna false - viu, não sou um animal :D
const numeros = [1, 2, 3, 4, 5]
include = numeros.includes(3)
console.log(include) //returna true
include = numeros.includes(0)
console.log(include) //returna false
// bora deixar interessante:
const arrayDeObj = [
{ id: 1, desc: 'Obj 1' },
{ id: 2, desc: 'Obj 2' },
]
include = arrayDeObj.includes(4) //?
console.log(include) // ia me assustar se retornasse true
include = arrayDeObj.includes({}) //?
console.log(include) // tambem retorna false
include = arrayDeObj.includes({ id: 1, desc: 'Obj 1' })
console.log(include) //retorna false WTF ?!
O includes foi muito bem até começarmos a trabalhar com objetos dentro dos arrays.
Mas isso é lógico, afinal o includes faz uma comparação simples, e para trabalharmos com comparação de objetos temos que ter uma certa cautela e complexidade na comparação de valores e elementos que esse objeto possa ter… mas aí é pra outro texto…
Agora vamos ao exponcencial, que também é bem simples:
//exponencial
const elevarA2 = (num) => num ** 2
console.log(elevarA2(5)) // retorna 25
const elevarA3 = (num) => num ** 3
console.log(elevarA3(5)) // retorna 125
Para realizar uma operação de "elevar um número" ao quadrado, cubo, afins, você pode fazer isso com o operador "**" igual na imagem aí em cima, e passar após o operador o valor que você vai elevar o número.
Sussa né ?! Link do repl com o código: https://repl.it/@jonathanjuliani/es7-includes
ES8
Vamo pra cima das (acredito eu) principais features do ES8, que você pode já ter utilizado e nem sabia ou não achava que fazia parte do ES8:
- String pad com "padStart" e "padEnd"
- Object.values
- Object.entries
pad
O padStart e padEnd adicionam ao começo ou final da string o número de espaços informado no parametro:
const name = 'Jonathan'
console.log(name.padStart(10))
// Jonathan//<= tem um pad de 10 espaços no começo
console.log(name.padEnd(10))
//Jonathan //<= tem um pad de 10 espaços no final
Object.values
Vamos ao Object.values, esse carinha retorna em formato de array todos os valores das keys de um objeto:
const obj = {
id: 1,
name: 'teste',
desc: 'teste description',
}
// retorna as entradas do obj em formato de array
const values = Object.values(obj)
console.log(values)
// [ 1, 'teste', 'teste description' ]
Super simples né ? Então já sabe, tem um objeto e precisa só dos valores dele, use o Object.values.
Object.entries
E o irmão maior dele o Object.entries retorna no mesmo formato de array todas as "entradas" e seus respectivos valores de um objeto, ele forma um array com a chave e o valor dentro:
const obj = {
id: 1,
name: 'teste',
desc: 'teste description',
}
// retorna as entradas do obj em formato de array
const entries = Object.entries(obj)
console.log(entries)
// [
// [ 'id', 1 ],
// [ 'name', 'teste' ],
// [ 'desc', 'teste description' ]
// ]
Com os dois métodos nós conseguimos com maior facilidade acessar os valores, ou as chaves de um objeto, transformados em array, deixando mais fácil a iteração nesses carinhas, a partir daí, conseguimos usar um for, um map, reduce, etc para realizar alguma operação.
top né?
Se tiver algum exemplo bacana pra me citar de uso desses carinhas eu ficarei contente.
Link do repl: https://repl.it/@jonathanjuliani/es8-features
ES9
Nesse release (se é que posso dizer dessa forma) temos umas coisinhas interessantes no JS, e algumas você pode até já ter utilizado, e nem sabia que chegou praticamente ontem haha, são algumas delas:
- Spread operator em objetos
- finally
- for await
spread
O spread já funcionava bem com arrays (vou criar um post sobre isso em algum momento, deixa um comment se quiser), mas com objetos não era muito legal até o ES8. Podemos agora definir ou receber um objeto e extrair dele o que quisermos para utilizar em determinada função/método e o "resto" podemos jogar em uma váriavel (de nome qualquer - geralmente 'rest') com o spread operator '…rest' e repassar ou utilizar o esse "resto" das informações do objeto quando necessário e/ou em outro lugar:
//object spread operator
const obj = {
id: 1,
nome: 'Jonathan',
bio: 'Fullstack developer - lorem ipsum cansei de escrever',
}
const { id, ...rest } = obj
console.log(id)
// 1
console.log(rest)
// {
// nome: 'Jonathan',
// bio: 'Fullstack developer - lorem ipsum cansei de escrever'
// }
Podemos criar um novo objeto (cópia) que não irá ser a mesma referencia de memória utilizando o spread, assim não precisamos utilizar por exemplo o Object.assign, se liga:
const obj2 = { ...obj }
console.log(obj2)
// { id: 1,
// nome: 'Jonathan',
// bio: 'Fullstack developer - lorem ipsum cansei de escrever' }
E podemos extrair qualquer informação do objeto, e deixar qualquer "resto", seja uma informação que é a primeira key do objeto ou a ultima key, ou em qualquer lugar no meio do objeto, ou seja a "posição" da key não importa:
const { nome, ...restoDoObj } = obj
console.log(nome)
// Jonathan
console.log(restoDoObj)
// { id: 1,
// bio: 'Fullstack developer - lorem ipsum cansei de escrever' }
finally
Se você já programa, provavelmente em alguma linguagem que você usou já deve ter o finally. Pois é, no JS demorou um pouco mas chegou, agora podemos usar no try/catch e nas promises o finally. No exemplo abaixo faço um fetch de uma api básica, e utilizo o finally para imprimir uma string no console. Podemos ver até que o finally executa antes do fetch terminar.
Exemplo:
const url = 'https://2jsonplaceholder.typicode.com/users'
const fetchUsers = async () => {
const data = await fetch(url)
.then((data) => console.log(data))
.catch((err) => console.log('Ish, deu ruim...'))
.finally(console.log('Não importa o que aconteça, estou aqui.'))
}
fetchUsers()
for await
Esse pode ser mais tretinha de pegar o jeito, eu não entendi de primeira, e não sei se faço do nada sem dar uma olhada em algum lugar.
Ele é tipo pra você fazer um for, e um await tudo junto, manja quando você tem 10 urls que precisa fazer fetch() ? Aí ou você vai lá e faz um Promise.all(fetch(url1), fetch(url2)…) e assim vai, ou sei lá, você faz 10 await, tipo await1, await2, await3,… não faça isso xD, ou faça, quem sou eu?! Haha Vamos ao exemplo básico seguindo o passo a passo: criamos/temos algumas urls, dai criamos uma function que vai fazer o fetch() dessas urls, então criamos um array de fetchs(), e utilizamos o for await para esperar esses fetchs, dentro do for realizamos o console.log dos resultados:
// 3 urls:
const urls = [
'https://jsonplaceholder.typicode.com/users',
'https://jsonplaceholder.typicode.com/posts',
'https://jsonplaceholder.typicode.com/albums',
]
//fetch das 3 urls usando for await
const fetchData = async (urls) => {
const fetchArray = urls.map((url) => fetch(url))
for await (result of fetchArray) {
const data = await result.json()
console.log(result)
}
}
fetchData(urls)
ES10
Estamos em 2019! Se você leu a parte do ES9 você deve ter visto que eu falei que teríamos uns negócio interessante aqui tipo flat array. Mas que %arai é isso? Vamo lá, segue nossa listinha:
- flat e flatMap
- Object.fromEntries
- trimStart e trimEnd
- catch sem parâmetro
- sort() sempre "stable"
flat
Pra começar, esse não vai ter link do repl pois algumas features tipo o flat() que vamos ver agora não estão funcionando por lá, então é melhor você tentar replicar (se quiser testar) aí no console do seu navegador desde que ele não seja de 1997. Agora bora para o flat.
O flat é um carinha novo no prototype dos Arrays, o que ele faz é basicamente pegar sub arrays (arrays filhos dentro de um primeiro array ) e jogar os valores para o array pai, to falando aqui de uma forma bem simplista. Melhor vermos um exemplo básico para deixar mais claro:
const array = [1, 2, [10, 20]]
console.log(array.flat())
Executa aí, viu que top? o flat() pegou o array filho [10,20] e "colocou" esses valores no array pai.
E como eu sou mais chato, um novo teste, mas o flat(). Só que vou te falar agora um detalhe: o flat() aceita que você passe pra ele um parâmetro que é tipo o número de flats que serão executados, então você não precisa fazer flat().flat() até o infinito e além, basta usar o flat(Infinity) por exemplo, se liga:
const array = [
1,
2,
[10, 20, [100, 200, [1000, 2000, [1, 4, 5, 6], [134, 1234, 5666, 77, [12, 15, 6]]]]],
[50, 38, 80],
]
console.log(array.flat(Infinity))
flatMap
O flatMap é como se você fizesse um map() no array, e depois um flat. Ou seja, você itera cada item do array para fazer alguma coisa, e depois faz um flat para juntar esse resultado ao seu array final.
Vamos ver um exemplo básico:
const array = [1, 2, 3, 4]
console.log(array.flatMap((value) => [value, value * 2]))
// [2, 4, 6, 8]
Na exemplo acima temos um array simples com os valores [1,2...] e utilizando o flatMap() nós conseguimos iterar os dois itens do array principal, e pra cada item retornamos o próprio item, e o item x 2, retornamos isso em um array, que em vez de ser criado dentro do array principal ele já é "flateado" tornando-se um array único, isso ocorre em todos os índices até termos um array único. Vou deixar para vocês brincarem mais com o flatMap por aí.
Object.fromEntries
Lembra que temos o Object.entries() que retorna em um formato de array todos os pares key/value de um objeto?
O fromEntries() faz exatamente o contrário, ele transforma um array de pares chave/valor em um novo objeto, como no exemplo abaixo, onde crio um obj, recupero as "entries" dele e re-crio o mesmo objeto em outra variável/memória com esses valores:
De boa né? E pode ser muito útil, as vezes você tem um backend ou banco de dados que retorna tudo em formatos de arrays, dessa forma você pode conseguir transformar em um objeto e trabalhar melhor em cima dos dados.
trimStart e trimEnd
Conforme falado no próprio site do EcmaScript o trimStart e trimEnd vieram como alternativas de nome melhor comparadas ao trimLeft e trimRight que já existem. Mas tem a mesma função, que é retirar espaços em branco no início ou final de uma string:
Obs: fiz um console.log com JSON.stringfy() para que ficasse melhor pra ver os espaços no começo e final da string. De forma alguma precisa utilizar alguma coisa do JSON.
catch sem parâmetros
Nem sempre quando vamos utilizar um catch() queríamos utilizar o parametro, e pode falar a verdade, você já fez um console.log(err) só pra o "err" não ficar lá "sem ser utilizado". É assim mesmo, mas agora podemos utilizar o catch sem declarar o parametro, utilizando direto as chaves:
catch {
}
sort() "stable"
Eu não vou explicar aqui sobre algoritmos, ou algoritmos stable vs unstable muito a fundo. Mas é necessário ter uma base pra você entender uma diferença básica.
Explicando na versão mais simplista possível, quando vamos ordenar um array de items, ao realizar as comparações para decidir se troca ou não os itens de posição um algoritmo pode ser: Stable: não troca de posição items que tem mesmo "valor". Unstable: pode trocar o item de mesmo "valor" de lugar um com o outro item de mesmo valor.
Se liga:
Em um algoritmo "unstable" os valores A e B, e também D e C poderiam estar com as posições trocadas, mas em um algoritmo "stable" eles mantém a posição original a qual já estavam no array.
Com ES10 todo sort() deve ser stable, e isso é uma nova exigência, então caso você teve problemas ou algo do tipo com um sort() unstable agora não vai se preocupar mais. :D
Quer saber mais sobre unstable vs stable?
Coloca nos comentarios que faço um post sobre. Se viu alguma cagada me fala, sentiu falta de algo me fala, vamos compartilhar conhecimento e código, é o melhor jeito de aprender e lembrar das coisas na minha opinião.