Olá Habr!
Hoje começaremos a falar sobre um tópico muito importante - programação funcional. É difícil superestimar a importância do FP no desenvolvimento moderno da web. A arquitetura de qualquer grande projeto moderno inclui bibliotecas de funções definidas pelo usuário, e haverá perguntas obrigatórias sobre o assunto das entrevistas em qualquer nível.
Introdução à Programação Funcional
A programação funcional (FP) é uma maneira de organizar o código escrevendo um conjunto de funções.
O EcmaScript, sendo uma linguagem de programação multiparadigma, implementa, entre outros, um paradigma funcional. Isso significa que as funções no ES são dados e podem ser passadas para funções, retornadas de funções e podem aceitar as próprias funções. I.e. funções no ES são
funções de primeira classe .
As seguintes definições seguem a seguir:
Argumento funcional (funarg) - um argumento cujo valor é uma função.
Uma função de ordem superior (FWP, função de ordem superior, hof) é uma função que aceita funções como argumentos.
Funções com um valor funcional (funções com valor de função) - uma função que retorna uma função.
Todos esses tipos de funções são combinados condicionalmente em funções da primeira classe e, como segue a definição acima, no ES todas as funções são objetos da primeira classe.
Funções puras - o ideal de programação funcional
Funções puras (PF) - sempre retornam um resultado previsto.
Propriedades PF
- O resultado da execução do PF depende apenas dos argumentos passados e do algoritmo que implementa o PF
- Não use valores globais
- Não modifique valores externos ou argumentos passados
- Não grave dados em arquivos, bancos de dados ou em qualquer outro lugar
Um exemplo de uma função pura:
const add = (x,y) => x+y;
Um bom exemplo de impureza da função é:
var first; var second; function testFn() { var a = 10; first = function() { return ++a; } second = function() { return --a; } a = 2; first();
Imagine como é complicado escrever testes para este exemplo e o quanto isso simplifica para funções puras!
As funções impuras são caracterizadas por um estado externo variável no tempo que complica a manutenção, a compreensão e o teste do código.
Pelo contrário, funções puras são sempre legíveis, testáveis, simplificam a paralelização de cálculos e são fáceis de reutilizar.
Acho que você notou que nos exemplos de funções puras, mudei para a sintaxe ES6. Isso foi feito deliberadamente. Essa sintaxe da função é chamada de "funções da seta", mas na verdade é uma implementação da abstração matemática, inventada há muito tempo. Sobre isso mais.
Lambda - funções
É assim que essa forma de escrita em seta é chamada em matemática e em algumas outras linguagens de programação. A programação funcional está intimamente relacionada ao mat. análise, por isso não se surpreenda.
O termo cálculo Lambda foi introduzido nos anos 30 pela Igreja Alonzo. Em essência, o cálculo lambda nada mais é do que uma forma formal de descrever uma equação matemática. Mais detalhes
aqui .
No ES, uma função lambda frequentemente implementa um fechamento:
const add = x => y => x + y;
Curto e conciso. A função add é uma lambda que recebe um argumento x, armazena-o em um fechamento e retorna uma função.
Compare com este código:
funtion add(x) { return function (y) { return x + y; } }
Obviamente, a primeira opção parece melhor.
Imunidade
Imutável (imutável, imunidade) é um objeto cujo estado não pode ser alterado após a criação. O resultado de qualquer modificação de um objeto desse tipo sempre será um novo objeto, enquanto o objeto antigo não será alterado.
A imutabilidade é o graal de ouro da programação funcional.
Considere um exemplo:
const impureAddProp = (key, value, object) => { object[key] = value;
Como você pode ver, neste exemplo, modificamos o objeto User adicionando uma propriedade a ele. Agora, o objeto Usuário é um tipo de "estado compartilhado" para a função impureAddProp e outras funções que o modificarão. Essa abordagem é mais difícil de testar porque Ao alterar qualquer função que interaja com um estado compartilhado, deve-se sempre ter em mente possíveis erros em outras funções.
Do ponto de vista da programação funcional, seria correto:
const pureAddProp = (key, value, object) => ({ ...object, [key]: value }); const User= { name: 'Alex' }; const Admin= pureAddProp ('isAdmin', true, User);
Portanto, o objeto Usuário permanecerá inalterado. Estamos modificando uma cópia dos dados, o que é sempre seguro.
Conclusão
Hoje examinamos vários conceitos teóricos importantes. Nós nos familiarizamos com funções puras, a forma lambda de funções de gravação e o conceito de imutabilidade em fp. No entanto, este artigo é um tipo de introdução. As principais idéias, técnicas e "partes difíceis" da programação funcional estarão nos seguintes artigos.
A programação funcional é implementada por muitas bibliotecas. Isso é rambda, e lodash, e muitos outros. Em um projeto real, é claro que você os usará. Sob o capô de qualquer biblioteca, ainda haverá o mesmo javascript nativo; portanto, nos artigos a seguir analisaremos o FP, implementando todos os seus conceitos no JS nativo.
Postscript
Começando a escrever artigos, eu tinha em mente o seguinte plano:
- escreva traduções de artigos interessantes em inglês
- destacar várias áreas relevantes em JS (conceitos-chave, OOP em termos de especificações EcmaScript, padrões, programação funcional).
Até o momento, os artigos principais em três áreas já foram escritos:
- this e ScopeChain no EcmaScript - aqui descrevi conceitos-chave da especificação como o contexto de execução, a palavra-chave this e a propriedade de contexto ScopeChain (cadeia de escopo). No contexto dessa direção, meu artigo sobre o ambiente e fechamento Lexical foi publicado literalmente hoje.
- Uma análise do EcmaScript sobre a teoria geral da OOP - aqui foi descrita a diferença entre tipagem de classe estática e organização dinâmica de protótipos, o modelo de delegação e a tipagem de pato foram desmontados
- Padrões elegantes no JavaScript moderno (série de compilação Bill Sourour no ciclo) - aqui estão dois padrões que podem ser úteis em algumas situações. Minha abordagem em termos de padrões é bastante simples: é melhor conhecer o maior número possível de padrões, porque mais cedo ou mais tarde, será útil
E agora é a vez da programação funcional. No futuro, escreverei artigos na continuação de cada uma dessas áreas. Por exemplo, o artigo a seguir será sobre os principais conceitos de OOP: encapsulamento, abstração, impurezas (e traços), interfaces, etc. ... também planejo falar sobre como o OOP no ES é implementado sob o capô, ou seja, sobre as propriedades de [[Prototype]], [[Class]] e muito mais. Fale sobre como a v8 cria entidades e instâncias de classes, funções.
Muitas perguntas surgem nos comentários, então eu gostaria de explicar as metas que estabeleci para meus artigos. Não escrevo tutoriais nem revisto a documentação. Na minha opinião, isso não faz sentido. Eu não aconselho você com certos instrumentos ou padrões, a escolha deles é inteiramente sua.
Nos artigos, reviso os conceitos, digo como eles estão organizados sob o capô (na minha opinião, isso melhora a compreensão do que escrevemos e por que escrevemos dessa maneira), ou falo sobre algumas coisas que ampliam meus horizontes. Na minha opinião, isso é muito importante. Dê uma olhada em empresas como Yandex ou Edadil, elas constantemente falam sobre algum tipo de idéias originais. Esses são bitmaps na reação, então o aplicativo vue está quase completamente nas classes es6. A maioria dos desenvolvedores da web nunca teria pensado nisso. Isso requer uma visão ampla.
Eu mesmo estudei e estudei a Web dessa maneira, ou seja, Depois de ler um tutorial ou uma doca, tento entender como a ferramenta descrita funciona sob o capô, para entender sua mecânica interna.
Até artigos futuros, amigos!