Introdução

Decidi enquadrar um pouco de programação funcional neste post sobre arrays pois nada mais justo do que mostrar o outro lado da força dos loops. A princípio, há alguns conceitos básicos para aprender: Funções puras, valores imutáveis, funções de primeira classe, recursividade e separação/modularização de responsabilidades. É importante lembrar que há um grande gap entre orientação à objetos e a herança clássica. Com isto em mente, vamos entender o que isto quer dizer.

O conceito

Programação funcional contém muitas palavras grandas e bonitas, porém o conceito é relativamente simples: Ao receber um valor em uma função, o resultado tem de ser previsível e constante, ou seja, sempre será igual não importa quantas vezes for chamado. Esta forma de organizar o código mantém o programa limpo e prático, inclusive na hora da documentação. Um simples exemplo pode ser colocado na seguinte forma:

  let num = 1;
  function impure () {
    return num++;
  }

  impure(); // 2
  impure(); // 3..

  let numTwo = 1;
  function pure (x) {
    return x * 2
  }
  pure(numTwo); // 2
  pure(numTwo); // 2
  pure(numTwo); // 2.........

Conforme mencionado, funções sem efeito colateral trazem uma beleza ao código e facilidade de leitura que vale o esforço de aprendizado. Acima, a função impure mantém o estado de num, onde a cada vez que ela é chamada o resultado é diferente. Já o impure pode ser chamado infinitas vezes que será previsível. Isto é apenas o início.

Você deve ter percebido que funções puras contém pelo menos um parâmetro que funciona como um filtro. Ao receber um tipo de valor ocorre uma transformação e um novo valor é retornado sem modificar o valor inicial. Entretanto, não é legal assumir que somente parâmetros são puros e ponto final.

Não manter estado (Stateless) e Funções de primeira classe (First class functions)

  let one = 1;
  function gotcha (x) {
    x - 10; // Mudando estado
    return 10;
  }
  gotcha(one); // 10
  gotcha(one); // 10...

  function firstClass (x) {
    return function (y) {
      return x * y;
    }
  }
  const example = firstClass(10);
  console.log(example); // example = (y) => 10 * y;
  const answer = example(20);
  console.log(answer); // 200

A explicação para a ocorrência acima é bem simples. Em gotcha, a função está manipulando o estado de x mesmo a resposta sendo 10 para inúmeras chamadas. Já em firstClass, o retorno é outro função e isto é devido ao fato que funções são passadas como objetos em Javascript e podem ser atreladas como valores. O mesmo poderia ser chamado assim:

  firsClass(10)(200);

  // Em node isto é altamente comum
  const port = 1337;
  const mongodb = require('Mongodb')(port);
  mongodb.connect( () => console.log(`Connected on port ${port}!`)); // Connected on port 1337!

Valores imutáveis

Certamente, isto não é algo tão comum nem tão fácil de replicar para os mais novos devs JS. Objetos são criados e modificados sem piedade pois não há compiladores reclamando nem index out of bounds ocorrendo. Com isto, a segurança de um servidor pode se danificar absurdamente quando feito sem perceber. Claro, há libs como o Immutable.js para ajudar com o fato, mas para situações mais simples não há necessidade. O próprio JS contém funções que ajudam com isso, mesmo que com certas limitações, sendo esta o Object.freeze. O Object.freeze impede que novas propriedades sejam adicionadas ou removidas e impede que a configuração via Object.defineProperty seja modificado. Só não esqueça de uma coisa: os valores das propriedades podem sim ser modificados, então na essência isto não é um objeto 100% imutável.

  'use strict';
  // Retorna o objeto posto imutável ou um novo objeto imutável
  var cantTouchThis = function (obj) {
    return Object.freeze(typeof obj === 'object' ? obj : {});
  }

  let immutable = cantTouchThis({
    inside: {
      name: 'Jonathan'
    }
  });
  immutable.inside.name = "John"; // Ok, pois somente se o objeto -> 'inside' também tomasse freeze que seria imutável
  immutable.age = 21 // TypeError
  immtuable.inside = [] // TypeError
  delete immutable.inside // TypeError

Os objetos que tentam ser modificados fora do use strict não jogam erro em tempo de execução mas não modificam nada. Já ao usar o use strict o compilador o rejeito com TypeError. Também é importante notar que o nível de freeze é somente 1.

Recursividade

Nada mais do que uma função chamando a mesma função declarada até que o resultado desejado aconteca. Simples e sem loops! Quem nunca teve que fazer um fatorial? Eu pelo menos achava um saco na escola.. Talvez fosse porque não conhecesse computação a fundos pois hoje acho 10/10. Isto faz parte de programação funcional pois nenhum tipo de loop é usado e sim chamadas infinitas e modularizadas. Bom, segue o exemplo:

function factorialize (num) {
  if (num === 1 || num === 0) return 1;
  else if (num === 2) return 2;
  else if (num > 2) {
    return num * factorialize(num - 1);
  }
}

const result = factorialize(5);
console.log(result); // 120

Praticando

O grande Eric Elliot publicou um post no medium onde a ideia era explciar um pouco sobre programação funcional com grande profundidade, e no final ainda tem um exercício bônus(Este abaixo) que ajuda bastante a fixar isto na mente. Seria ideal que vocês ao menos tentassem pois vale muito a pena. Para quem ainda não conseguiu, segue minha forma resolvida do problema.

See the Pen MyojLq by Eric Elliott (@ericelliott) on CodePen.

Recomendação

Estes caras do freecodecamp são uns monstros nos exercícios! Há dos mais básicos até o nível expert sem dó. Recomendo para todos querendo aprender/se aprofundar em Javascript.

Este link é sinceramente as explicação mais absurda e bem escrito da internet na minha opinião. Nele há uma grande quantidade de exercícios seguidos de explicação em Javascript sobre programação funcional. Ao fazê-lo, você rapidamente pega o jeito de recursividade, funções puras e usabilidade em geral, e nisso eu dou a minha palavra. O autor deste post é o Jafar Hussain, grande mestre de Javascript que trabalha na netflix. Recomendo fortemente seguir este ser humano no Twitter, Github, facebook, etc pois além de entendedor do assunto o cara é fera demais explicando. Para quem quiser ou tiver grana para gastar no aprendizado o Frontend Masters tem um curso de Asynchronous Programming in Javascipt (With Rx.js Observables) onde ele explica em detalhes tudo isto que dei uma breve introdução sobre. Realmente vale 100% do valor agregado neste curso, recomendo fortemente.

Por hoje é só. Um abraço!