Currying, hoisting e immutability

3 conceitos interessantes sobre o uso do javascript

SHARE:

Currying

Em ciência da computação, currying é uma técnica de transformação de uma função que recebe múltiplos parâmetros de forma que ela pode ser chamada como uma cadeia de funções que recebem somente um parâmetro cada.

O currying é bem comum em linguagens funcionais! O javascript não é uma linguagem funcional por padrão, mas você consegue escrever código funcional!

Com o currying, você pode reutilizar e criar diferentes versões e também criar versões intermediárias das funções.

Função normal:

function soma(a, b) {
  return a + b
}

soma(2, 2)
soma(2, 3)
soma(2, 4)
soma(2, 5)

Perceba que o primeiro argumento está sendo repetido ao chamar a função soma()! Podemos aplicar essa técnica currying na função para evitar esta repetição, portanto, para cada parâmetro vamos criar uma nova função.

Com currying

function soma(a) {
  return function(b) {
    return a + b
  }
}

const somaCom2 = soma(2)

somaCom2(2)
somaCom2(3)
somaCom2(4)
somaCom2(5)

Veja que agora a função soma() não recebe mais dois valores, ela recebe apenas um valor e, em seguida, dar um return em uma função que recebe o segundo valor. Essa função, por sua vez, retorna valor a mais o valor b.

Hoisting

As variáveis declaradas com var serão adicionadas no topo do escopo de uma função (se forem colocadas dentro de uma), ou no topo do escopo global (se forem declaradas fora de uma função), independentemente de onde a declaração real ocorrer. Isso essencialmente é “hoisting”.

Hoisting é, basicamente, o comportamento que ocorre no javascript na declaração de variáveis e funções. Elas são elevadas no escopo!

O hoisting de variáveis só eleva a CRIAÇÃO e não sua ATRIBUIÇÃO, já a função é elevada ao topo como um todo.

Variáveis

function fn() {
  console.log(text)
  
  var text = 'exemplo' // a variavel está sendo declarada depois do console
  
  console.log(text)
}

O código acima seria o mesmo que este abaixo:

function fn() {
  var text;
  
  console.log(text) // undefined
  
  text = 'mandy'
  console.log(text) // mandy
 }

No primeiro código, observe que foi criada uma função que, dentro dela, é feito o console da variável text no qual foi declarada embaixo, mas se você for tentar usar a variável que não foi declarada ainda, provavelmente vai dar erro pois não existe! No javascript, por causa do hoisting, o comportamento vai ser como está no segundo código. Se eu tenho um var text, ele vai declarar a variável lá no topo SEM o seu valor, portanto, no primeiro console vai retornar undefined pois ainda não possui valor, porém a variável existe!

Por isto é importante que usemos let e const, já que o interpretador expõe explicitamente um erro de Referência. Isso garante que sempre declaremos nossa variável primeiro. :)

Função

function fn() {
  log('Hoisting de função')
  
  function log(value) {
    console.log(value)
  }
}

fn()

O código acima seria o mesmo que este:

function fn() {
  function log(value) {
    console.log(value)
  }

  log('Hoisting de função')
}

A diferença aqui é que a função é elevada ao topo, então quando for chamado a função log(), por mais que esteja antes da declaração da função, eu vou conseguir executar!

Imutabilidade

Este é outro conceito de linguagem funcional que temos no javascript. Os dados que criamos nunca mudam. A variável nunca vai mudar, e, se você precisar alterar ela, você cria uma nova! Então, ao invés de você mudar um array por exemplo, você cria um novo array baseado no que se quer alterar, e pra adicionar é só pegar todo o array e concatenar. Para remover um elemento podemos filtrar o array por exemplo. Assim como o objeto, ele nunca é atualizado, ele vai ser COPIADO e você altera só o que quiser :)

Quando estamos falando de imutabilidade em JavaScript estamos falando em evitar modificar referências.

const user = {
  name: 'Amanda',
  lastName: 'Almeida Matos'
}

function getUserWithFullName(user) {
  return {
    ...user,
    fullName: `${user.name} ${user.lastname}`
  }
}

const userWithFullName = getUserWithFullName(user)

console.log(userWithFullName)

Veja que neste exemplo temos uma função que recebe o objeto user e adiciona um novo atributo que é o nome completo (fullName). Eu passo um user como parâmetro e daí será retornado o nome, ultimo nome e nome completo.

A ideia da imutabilidade é que, por exemplo, toda vez que passarmos pra função um objeto ou array, ele é passado por referencia, ou seja, se você alterar ele, ele vai estar alterando o mesmo local que a variável aponta, não vamos alterar um user e sim criar um novo.

Outro exemplo de imutabilidade utilizando filter:

const students = [
  {
    name: 'Leonardo Da Vinci',
    grade: 10
  },
  {
    name: 'Van Gogh',
    grade: 7
  },
  {
    name: 'Claude Monet',
    grade: 4
  }
]

function getApprovedStudents(studentsList) {
     return studentsList.filter(student => student.grade >= 7)
}

console.log('Alunos aprovados')
console.log(getApprovedStudents(students))

console.log('Lista de alunos')
console.log(students)

Algumas orientações sobre imutabilidade:

  • Escreva funções que retornam cópias alteradas do objeto ao invés de alterar as propriedades do objeto especificado.

    // Ruim
    function save(object){
      object.saved = true;
      return object;
    }
    
    // Bom
    function save(object){
      let newObject = object.clone();
      newObject.saved = true;
      return newObject;
    }
  • Se você tem objetos que mudam com muita frequência, não é a melhor ideia criar uma nova instância para cada alteração.

E aí? curtiu? (◠‿◕✿)

Comentários

Prefere comentar em ânonimo? Siga os seguintes passos:

  • Clique no campo "Nome"
  • Marque os itens necessários, principalmente o último: "Prefiro publicar como um visitante"
  • Adicione um email
  • Agora só enviar seu comentário :)