Categorias
JavaScript Tutoriais

5 maneiras de utilizar o Spread operator

Spread operator parameter foi introduzido no EcmaScript 2015, para um simples recurso no primeiro momento mas utilizados da maneira correta pode se tornar bastante útil, o se você ainda não conhece o spread operator é identificado por “três pontos(…)” com ele podemos desmontar arrays e objetos. Nesse post iremos ver 5 maneiras de utilizar o spread operator.

1. Combinando arrays

Primeiro exemplo podemos ver como podemos combinar dois arrays ou mais, exemplo:

let semana = ['segunda', 'terça', 'quarta', 'quinta', 'sexta']; 
let semanaCompleta = ['domingo', ... semana, 'sábado']; 

console.log(semanaCompleta)

// output:  ['domingo', 'segunda', 'terça' 'quarta', 'quinta', 'sexta', 'sábado'];

2. Copiando array

Um dos problemas de copiar um array para outra variável, caso passamos a referencia diretamente, não estamos fazendo uma cópia do array e sim uma referência ao primeiro array, como no código abaixo:

let lista1 = [1,2,3]; 
let lista2 = arr;

lista2.push(4);
console.log(lista1);
// output : [1, 2, 3, 4]

Se testarmos o código acima temos como saída do console.log do “lista1” a alteração feita no “lista2”, isso acontece por que temos uma referência para lista1 e não uma copia do array. Para resolver este problema podemos utilizar o spread operator como uma alternativa para copiar a lista como no exemplo abaixo:

let lista1 = [1,2,3]; 
let lista2 = [...arr];

lista2.push(4);
console.log(lista1);
// output : [1, 2, 3]

3. Convertendo um nodeList em um array

Outra utilidade de utilizar o spread operator é converter items que parecem um array mas não são. Por exemplo, quando trabalhamos com querySelectorAll temos como retorno uma lista de items mas essa lista não é do tipo array, o retorno é um elemento nodeList outra função que retorna uma lista é getElementsByClassName mas o retorno dessa função é um HTMLCollection, e o qual é o impacto desses dois tipos?

NodeList and HTMLCollection apenas suportam a função forEach, caso queiramos fazer interações como map, filter, reduce ou sort. Funções referentes ao tipo Array teremos um error como retorno, como no exemplo abaixo.

let buttons = document.querySelectorAll('button');

let newList = buttons.map((button) => (button.innerText = button.innerText + ' Copy!'));

No exemplo acima, levamos em conta que nosso HTML tem uma série de elementos button e queremos realizar uma cópia desta lista de elementos, mas nosso código irá disparar um erro pois, map não é função dentro de um nodeList, para isso precisamos converte-lo em um array para isso utilizamos o spread operator, como no exemplo a seguir:

let buttons = [...document.querySelectorAll('button')];

let newList = buttons.map((button) => (button.innerText = button.innerText + ' Copy!'));

Agora sim, conseguimos executar o nosso código e criar uma cópia dos items selecionados, essa ação poderia ser uma ordenação ou um filtro para alterar elementos específicos. Mas é uma boa base para entender a diferença esses dois items claro que nodeList e HTMLCollection tem suas especificidades, eles estão contidos na browser API enquanto Arrays fazem parte da JavaScript API. Caso queria saber mais sobre esses dois items deixe um comentário.

4. Criando novos objetos

Assim como arrays caso queiramos copiar objetos teremos problemas com referência mas nesse caso podemos ir um pouco além, podemos criar novos objetos a partir de um objeto, por exemplo, em um ecommerce temos um objeto endereço, o usuário pode ter múltiplos endereços, quando ele requisita um entrega um novo objeto é criado com endereço que ele selecionou e o seu nome. Como no exemplo abaixo:

const usuario = { nome: 'fellyph cintra', telefone: '0000-0000' };
const endereco = { cidade : 'caruaru', estado: 'pernambuco' };

const entrega = {
  responsavel: usuario.nome,
  ...endereco
};

console.log(entrega);
//output: {responsavel: 'fellyph cintra', cidade: 'caruaru', estado: 'pernambuco'}

No exemplo acima utilizamos a apenas a propriedade nome do usuário, imagine que o objeto entrega precisa de todos os dados do usuário, nesse caso precisaremos combinar os dois objetos então o código ficará da seguinte forma:

const usuario = { nome: 'fellyph cintra', telefone: '00000-0000' };
const endereco = { cidade : 'caruaru', estado: 'pernambuco' };

const entrega = {
  ...usuario,
  ...endereco
};

console.log(entrega);
//output: {responsavel: 'fellyph cintra', telefone: '00000-0000', cidade: 'caruaru', estado: 'pernambuco'}

5. Excluindo propriedades

Voltando para o exemplo anterior imagine que o objeto usuário contém o email do usuário essa informação não será necessária para o objeto entrega imagine, podemos utilizar o spread operator para remover propriedades também, como no código a seguir:

const usuario = { nome: 'fellyph cintra', telefone: '00000-0000', email: 'pindolinha@gmail.com' };
const endereco = { cidade : 'caruaru', estado: 'pernambuco' };

const semEmail = ({ email, ...rest }) => rest;

const entrega = {
  ...semEmail(usuario),
  ...endereco
};

console.log(entrega);
//output: {responsavel: 'fellyph cintra', telefone: '00000-0000', cidade: 'caruaru', estado: 'pernambuco'}

No código acima, criarmos uma função chamada semEmail, nela separamos o email do resto do objeto e passamos como retorno o objeto sem a propriedade email.

Existem outros usos para o spread operator, como propriedades default ou propriedades condicionais, esses são os 5 usos mais básicos para spread operator. Caso tenha um uso particular que você gosta comente abaixo!

Até o próximo post!

Categorias
Tutoriais Web

Variáveis e funções com ECMAScript 2015

ECMAScript 2015 é nova especificação do JavaScript antes chamado de ECMAScript 6, por uma padrão de conversão e buscando implementações menores em pequeno prazo. Lembrando que esses recursos nem todos os browser rodam, o ideal é utilizar uma ferramenta para compilar seu código para browsers antigos, um dos mais utilizados é o Babel, ele possui um handbook em português que mostra instalação e como usar:

https://github.com/thejameskyle/babel-handbook/blob/master/translations/pt-BR/user-handbook.md

Boa parte dos exemplos eu rodei no Chrome sem precisar do babel, nesta página(ECMAScript 6 compatibility table) você tem uma tabela detalhada do suporte de cada browser. Para um projeto em produção é necessário o uso do babel. Agora voltando ao ECMAScript, ela vem com uma série de novidades, já mostrei alguns dos novos recursos nos posts sobre REACT, mas não entrei em detalhes neste post vou listar algumas das novidades.

Declarando variáveis

let

let é utilizado para declarar variáveis dentro de um escopo menor comparado ao var que tem um escopo global ou relacionado a funções, com o let o escopo pode ser limitado por blocos menores if, else, for e while.

const

const como em outras linguagens o permite nos criarmos variáveis read-only, constantes nos ajudam a criar códigos mais legíveis, exemplo quando lemos o seguinte código:

function doSomething(num) {
  if(num < 5) {
    //doSomething
  }

  for(var i = 0; i < 5; i++) {
    //doSomething
  }
}

Não temos idéia o que é o número 5, apenas um fator na condicional, se mudarmos para o seguinte código:

function doSomething(num) {
  const MAX_PRODUCTS = 5;
  
  if(num < MAX_PRODUCTS) {
    //doSomething
  }

  for(var i = 0; i < MAX_PRODUCTS; i++) {
    //doSomething
  }
}

Agora com as modificação batemos o olho sabemos que os loops estão limitados por um número máximo de produtos. Esse valor é escrito apenas uma vez, ele não pode ser alterado após ser definido. Por um padrão de escrita de código todas as constantes precisa ser escritas em uppercase.

Funções

Surgiram novas funcionalidades super úteis relacionadas a funções com ECMAScript 2015. A primeira delas, valores default na assinatura da funções. Um problema básico é acesso a variáveis undefined, temos um tratamento comum para isso da seguinte forma:

function listProducts(listOfProducts) {
  var products = typeof listOfProducts !== 'undefined' ? listOfProducts : [];
  var total = products.length;
  //do something
}

Com nova definição de EcmaScript 2015 podemos criar valores default sem precisar de um tratamento especial como a versão anterior da seguinte forma:

function listProducts(listOfProducts = []) {
  let total = listOfProducts.length;
  //do something
}

Nomeando parâmetros

Uma nova funcionalidade, agora é possível nomear parâmetros como isso é útil, no exemplo abaixo:

function setProduct(newProduct = {}) {
  product.name = newProduct.name;
  product.price = newProduct.price;
  product.category = newProduct.category;
}

Exemplo acima contornamos o problema do parâmetro “undefined” mas se os atributos não existirem nosso código irá disparar um erro.

function setProduct({name, price, category} = {}) {
  product.name = name;
  product.price = price;
  product.category = category;
}

Nomeando parâmetros, além do código ficar mais legível, não caímos nos problemas de atributos inválidos.

Rest Params

Outro novo recurso do ECMAScript 2015 é possível passar um array de parâmetros como argumento, como isso funciona, por exemplo, temos uma função de produtos relacionados onde podemos exibir, um, dois ou três produtos:

showRelacionados(“produto-1”);

showRelacionados(“produto-1”, “produto-2”, “produto-3”);

showRelacionados(“produto-1”, “produto-2”);

Você precisa passar um número x de argumentos que sempre variam, nunca é uma quantidade exata. Com parâmetros rest, permite definir que a função espera um array de argumentos.

function showRelated(...related) {
  for(let i in related ) {
    console.log(related[i]);
  }
}

showRelated("produto-1", "produto-2", "produto-3");

Além dos “…” na assinatura da função, podemos adicionar na chamada da função mas ela tem uma funcionalidade diferente quando acionamos a função, neste caso ela quebra os parâmetros do objeto em vários argumentos. Exemplo temos o objeto

produto.nome = “Prato”;
produto.preco = 20;
produto.categoria = “casa”;

adicionaProduto(…produto);

A função “adicionaProduto” irá receber 3 parâmetros(nome, preco e categoria).

Arrow function

Arrow function além de simplificar a escrita de funções ela mantém o escopo de quem invoca a função útil quando estamos tratando, também chamado de “lexical binding” ele cria um escopo de quem o define e não de onde ele roda, outro ponto a Arrow functions sempre são anônimas. Sua síntaxe é simples:

([parametro], [parametro]) => {
   //código que será executado na chamada da função
}

Exemplo temos um código sem arrow function:

var categorias =  ["casa", "jardim", "praia"];

categorias.map(function(prop) {
  console.log(prop);
});

Com arrow function ele fica da seguinte forma:

var categorias =  ["casa", "jardim", "praia"];

categorias.map(prop => {
  console.log(prop);
});

Apenas uma chamada mas imagine isso sendo repetido várias vezes no dia, mas outra vantagem é a questão do escopo um problema comum é perder o escopo quando você codando alguma funcionalidade exemplo:

function Clock() {
  this.time = 10; 
  
  setInterval(function count() {
    this.time++;
    console.log(this.time, this);
  }, 1000);
};

var c = new Clock();

Criamos um objeto tipo Clock, mas ele tem um problema quando usamos o console dentro do setInterval por exemplo o escopo do setInterval é global nesse momento o this não é o clock e sim o objeto Window. Claro que podemos resolver esse problema criando uma variável self para para o clock e guardar o this(clock) dentro dessa variável outra solução seria usar o arrow function:

function Clock() {
  this.time = 10; 
  
  setInterval( () => {
    console.log(++this.time, this);
  }, 1000);
};

var c = new Clock();

Vamos ficando por aqui o próximo post sobre ECMA irei falar sobre objetos e classes.