ES08 - Novas features no JavaScript

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! 🚀