ES08 - Novas features no JavaScript

JavaScript 26 de Ago de 2020

Neste post vamos ficar por dentro das novidades do ES08 (ECMAScript 2017) no JavaScript.

Se quiser ver o que rolou no ES07 recomendo a leitura desse post.

Padding String

String ganhou dois métodos novos: padStart() e padEnd(). Padding significa preenchimento, portanto, vamos ver como preencher uma String no começo e no final.

Método padStart() recebe dois parâmetros: o primeiro é o tamanho final da string após a execução do padding; e o segundo parâmetro é o caractere que vai preencher até alcançar o tamanho da String. O preenchimento é feito da esquerda para direita, isso é, do início da String até o final.

Veja abaixo alguns exemplos:

// Preenchendo dois zeros no começo da string
const filme = '7';
console.log(`${filme.padStart(3, '00')} - Sem Tempo Para Morrer`) 
// 007 - Sem Tempo Para Morrer

// Adivinhando o nome
const nome = "Thiago" // Nome para adivinhar.
const ultimaLetraDoNome = nome.slice(nome.length - 1)
console.log(`Uma dica: Termina com '${ultimaLetraDoNome}', e tem ${nome.length} letras`,) 
// "Uma dica: Termina com 'o', e tem 6 letras"

let adivinheMeuNome = ultimaLetraDoNome.padStart(nome.length, '*'); 
                                       
console.log(adivinheMeuNome) // Resultado: "*****o"
console.log(`Resposta correta: ${nome}`) // Resposta correta: Thiago

// Escondendo alguns dígitos do cartão de crédito
const cartaoDeCredito = '2034399002125581';
const ultimosQuatroDigitos = cartaoDeCredito.slice(-4);
const cartaoDeCreditoMask = ultimosQuatroDigitos.padStart(cartaoDeCredito.length, '*');
// Resultado: "************5581"

Mesma funcionalidade do padStart(), porém o preenchimento começa do fim (direita) da String. Se receber apenas um parâmetro, será adicionando um espaço vazio, ao invés de um caractere, caso receba apenas um parâmetro. Demonstramos no primeiro exemplo abaixo:

// Adicionando dois espaços em branco após: '200'
const string = '200';
console.log(string.padEnd(5)); // Resultado: "200  " 
// Observe que o tamanho da string é cinco passou a ser cinco.

// Array de números
const numbers = [1, 2, 3, 4, 5]
// Crio um novo array de Strings Adicionando ". " em cada número e converto para String.
const ordenedList = numbers.map(number => String(number).padEnd(3, '. '))
console.log(ordenedList) 
// Resultado: ["1. ", "2. ", "3. ", "4. ", "5. "]

// Adicionando reticências.
const txtLoading = 'Loading';
console.log(txtLoading.padEnd(10, '.')); //  "Loading..."

Trailing commas

Vírgulas no final. Para ser sincero não é muito útil. Difícil achar algum caso de uso para essa funcionalidade. Ela basicamente permite você colocar uma , após o último elemento de um array ou objeto, e não dará um erro de sintaxe.

// Exemplo com Array
const numbers = [1,2,3,]
console.log(numbers) // 1, 2, 3

// Exemplo com Objeto
const tech = {
	name: 'JavaScript',
  sigla: 'JS',
  age: 24,
}

Em funções também é possível colocar vírgulas no final:

function sum(n1, n2,) { return n1 + n2 }
sum(1,2) // 3 válido
sum(1,3,) // 4 válido

Mas claro que alguns erros de sintaxe podem ocorrer:

function sum(, ) { }

// Uncaught SyntaxError: Unexpected token ','

Vale a pena saber que existe, mas não é algo que é aplicado no dia a dia. Com uma regra no ESLint essas vírgulas no final são removidas automaticamente, caso prefira.

Objects: entries() e values()

  • Object.entries()

Retorna um array com chave e valor de cada atributo do objeto em um array: [ [name: 'Thiago'], [email: 'oi@email.com'] ] . O que torna possível fazer iteração entre cada propriedade utilizando o for ... of  como no exemplo abaixo:

const rocketseat = {
  backend: 'Node.js',
  frontend: 'React',
  mobile: 'React Native',
}

for (const [prop, value] of Object.entries(rocketseat)) {
  console.log(`${prop}: ${value}`);
}
// Saída:
/**
	backend: Node.js
	frontend: React
	mobile: React Native
*/
  • Object.values()

Retorna um array com os valores de cada atributo do objeto.

const rocketseat = {
  backend: 'Node.js',
  frontend: 'React',
  mobile: 'React Native',
}

// Antes
for (const key in rocketseat) {
  if (rocketseat.hasOwnProperty(key)) {
    const value = rocketseat[key];
    console.log(value); // "Node.js", "React", "React Native"
  }
}

// Abordagem Funcional - ES6
console.log(Object.keys(rocketseat).map((k) => rocketseat[k]));
// ["Node.js", "React", "React Native"]

// Hoje - ES8
console.log(Object.values(rocketseat));
// ["Node.js", "React", "React Native"]

// Outros exemplos com String:
console.log(Object.values('Rocksetseat')) 
// ["R", "o", "c", "k", "s", "e", "t", "s", "e", "a", "t"]
console.log(Object.entries('Rocksetseat'))
// [["0", "R"], ["1","o"] .... ["10", "t"]]

Object.getOwnPropertyDescriptors()

Retorna uma descrição do objeto que foi informado no parâmetro.

const rocketseat = {
  backend: 'Node.js',
  frontend: 'React',
  mobile: 'React Native',
}

console.log(Object.getOwnPropertyDescriptors(rocketseat))

// Resultado
/**
{
  backend: {
    value: 'Node.js',
    writable: true,
    enumerable: true,
    configurable: true
  },
  frontend: {
    value: 'React',
    writable: true,
    enumerable: true,
    configurable: true
  },
  mobile: {
    value: 'React Native',
    writable: true,
    enumerable: true,
    configurable: true
  }
}
*/

const arrayFunc = () => {}

console.log(Object.getOwnPropertyDescriptors(arrayFunc))

// Saida
/**
{
  length: { value: 0, writable: false, enumerable: false, configurable: true },
  name: {
    value: 'arrayFunc',
    writable: false,
    enumerable: false,
    configurable: true
  }
}
*/

Esse método ajuda a criar uma cópia profunda do objeto, de maneira que o clone do mesmo se torne fiel à sua matriz.

const rocketseat = {
  backend: "Node.js",
  frontend: "React",
  mobile: "React Native",
};

console.log(rocketseat);

// Clonando
const UICloneRocketseat = Object.defineProperties(
  {},
  Object.getOwnPropertyDescriptors(rocketseat)
);

// Resultado
console.log(UICloneRocketseat);
console.log(Object.getOwnPropertyDescriptors(UICloneRocketseat));

Funções Assíncronas

Melhoram a experiência da programação assíncrona. Async/Await são palavras reservadas que usamos em funções assíncronas. Com essa nova sintaxe podemos escrevê-las de maneira mais coesa. A quantidade de código não reduz muito, mas dá para perceber a sua clareza, veja os exemplos abaixo:

// Async Function
async function getUserUsingAsyncAwait(username) {
  try {
    const response = await fetch(`https://api.github.com/users/${username}`);
    return response.json()
  } catch (err) {
    console.log("Ops! Ocorreu um erro...", err);
  }
}
 
// Função com Promises
function getUserUsingPromises(username) {
  return fetch(`https://api.github.com/users/${username}`)
   .then(response => response.json())
    .then(json => {
     return json
    }).catch(err => {
      console.error('Ops! Ocorreu um erro...', err);
    });
}

// https://developer.mozilla.org/pt-BR/docs/Glossario/IIFE
// IIFE (Immediately Invoked Function Expression) 
// é uma função em JavaScript que é executada assim que definida.
(async function(){
  console.log(await getUserUsingAsyncAwait('vinifraga'))  
  console.log(await getUserUsingPromises('jpedroschmitz'))
})()

Veja o código funcionando no Codepen.

Outros exemplos:

function resolveDepoisDeDoisSegundos(x) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

(async function (x) {
  // async function expression usada como uma IIFE
  const a = resolveDepoisDeDoisSegundos(20);
  const b = resolveDepoisDeDoisSegundos(30);
  return x + (await a) + (await b);
})(10).then((valor) => {
  console.log(valor); // imprime 60 após 2 segundo.
});

const soma = async function (valor) {
  // async function expression atribuída a uma constante
  const a = await resolveDepoisDeDoisSegundos(20);
  const b = await resolveDepoisDeDoisSegundos(30);
  return valor + a + b;
};

soma(10).then((valor) => {
  console.log(valor); // imprime 60 após 4 segundos.
});

Conclusão

Sem dúvida nenhuma que Funções Assíncronas é a feature mais utilizada e útil desse lançamento. Você precisa aprender para alcançar o próximo nível e deixar o código mais legível, Async/Await é um syntactic sugar que deixa o código mais agradável, se quiser saber quando usar Async/Await ou sobre Promises no Frontend com React dá uma lida aqui.

Object.values() e Object.entries() são bastantes utilizadas também no dia a dia.

O método Object.getOwnPropertyDescriptors() creio que é o menos utilizado até porque para fazer cópias de objetos podemos utilizar o Object.assign() ou o famoso e apreciado Spread Operador.

E aí, o que achou do post?

Espero que tenha curtido! 💜

O aprendizado é contínuo e sempre haverá um próximo nível! 🚀

Marcadores

Thiago Marinho

Dev Apaixonado por Tecnologia & Educação! Evolua rápido como a tecnologia, aprendizado é contínuo e sempre haverá um próximo nível. Boost Yourself! 🚀