Funções de ordem superior em JavaScript

Se você está aprendendo JavaScript, deve ter se deparado com o conceito de "Função de Ordem Superior". Isso pode parecer algo muito complicado, mas, de fato, não é.

JavaScript é adequado para programação funcional porque suporta o conceito de funções de ordem superior. Tais funções são amplamente usadas na linguagem e, se você programou em JS, provavelmente já trabalhou com elas sem nem mesmo saber.



Para entender completamente esse conceito, primeiro você precisa entender o conceito de programação funcional (Programação Funcional) e quais funções são de primeira classe (Funções de Primeira Classe).

O material, cuja tradução publicamos, é destinado a iniciantes, visa explicar o conceito de funções de ordem superior e demonstrar como usá-las em JavaScript.

O que é programação funcional?


Se você descrever o conceito de programação funcional em palavras simples, verifica-se que essa é uma abordagem da programação, usando a qual você pode passar funções para outras funções como parâmetros e usar funções como valores retornados por outras funções. Participando da programação funcional, projetamos a arquitetura do aplicativo e escrevemos código usando funções.

Entre as linguagens que suportam programação funcional estão JavaScript, Haskell, Clojure, Scala e Erlang.

Funções de primeira classe


Se você estiver aprendendo JavaScript, poderá ouvir que em um idioma as funções são tratadas como objetos de primeira classe. Isso ocorre porque no JavaScript, como em outros idiomas que suportam programação funcional, as funções são objetos.

Em particular, em JS, as funções são representadas como objetos de um tipo especial - esses são objetos do tipo Function . Considere um exemplo:

 function greeting() { console.log('Hello World'); } //   greeting();  //  'Hello World' 

Para provar que funções em JavaScript são objetos, podemos fazer o seguinte, continuando o exemplo anterior:

 //     ,       greeting.lang = 'English'; //  'English' console.log(greeting.lang); 

Observe que, ao adicionar suas próprias propriedades a objetos padrão no JavaScript não causa mensagens de erro, isso não é recomendado. Você não deve adicionar suas próprias propriedades às funções. Se você precisar armazenar algo em um objeto, é melhor criar um objeto especial para isso.

No JavaScript com funções, você pode fazer o mesmo com entidades de outros tipos, como Object , String , Number . As funções podem ser passadas como parâmetros para outras funções. Tais funções, transferidas para outras pessoas, geralmente agem como funções de retorno de chamada (retornos de chamada). As funções podem ser atribuídas a variáveis, armazenadas em matrizes e assim por diante. É por isso que funções em JS são objetos de primeira classe.

Atribuindo funções a variáveis ​​e constantes


As funções podem ser atribuídas a variáveis ​​e constantes:

 const square = function(x) { return x * x; } //   25 square(5); 

As funções atribuídas a variáveis ​​ou constantes podem ser atribuídas a outras variáveis ​​ou constantes:

 const foo = square; //  36 foo(6); 

Passando funções como parâmetros


As funções podem ser passadas como parâmetros para outras funções:

 function formalGreeting() { console.log("How are you?"); } function casualGreeting() { console.log("What's up?"); } function greet(type, greetFormal, greetCasual) { if(type === 'formal') {   greetFormal(); } else if(type === 'casual') {   greetCasual(); } } //  'What's up?' greet('casual', formalGreeting, casualGreeting); 

Agora que sabemos como as funções de primeira classe se comportam, vamos falar sobre funções de ordem superior.

Funções de ordem superior


Funções de ordem superior são funções que funcionam com outras funções, tomando-as como parâmetros ou retornando-as. Simplificando, uma função de ordem superior é uma função que aceita uma função como argumento ou retorna uma função como um valor de saída.

Por exemplo, as funções JavaScript Array.prototype.map , Array.prototype.filter e Array.prototype.reduce são funções de ordem superior.

Funções de ordem superior em ação


Considere exemplos de uso de funções de ordem superior incorporadas ao JS e compare essa abordagem com ações semelhantes sem usar essas funções.

▍ Método Array.prototype.map


O método map() cria uma nova matriz, chamando, para processar cada elemento da matriz de entrada, o retorno de chamada passado como argumento. Este método pega todo valor retornado pelo retorno de chamada e o coloca na matriz de saída.

A função de retorno de chamada passada para map() leva três argumentos: element (elemento), index (índice) e array (matriz). Vejamos alguns exemplos.

Exemplo No. 1


Suponha que temos uma matriz de números e queremos criar uma nova matriz que contenha os resultados da multiplicação desses números por 2. Considere maneiras de resolver esse problema usando funções de ordem superior e sem elas.

Resolvendo um problema sem usar funções de ordem superior


 const arr1 = [1, 2, 3]; const arr2 = []; for(let i = 0; i < arr1.length; i++) { arr2.push(arr1[i] * 2); } //  [ 2, 4, 6 ] console.log(arr2); 

Resolvendo um problema usando um mapa de funções de ordem superior


 const arr1 = [1, 2, 3]; const arr2 = arr1.map(function(item) { return item * 2; }); console.log(arr2); 

Você pode até reduzir o volume desse código se usar a função de seta:

 const arr1 = [1, 2, 3]; const arr2 = arr1.map(item => item * 2); console.log(arr2); 

Exemplo No. 2


Suponha que temos uma matriz contendo o ano de nascimento de algumas pessoas e precisamos criar uma matriz que atinja a idade em 2018. Considere, como antes, a solução para esse problema de duas maneiras.

Resolvendo um problema sem usar funções de ordem superior


 const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = []; for(let i = 0; i < birthYear.length; i++) { let age = 2018 - birthYear[i]; ages.push(age); } //  [ 43, 21, 16, 23, 33 ] console.log(ages); 

Resolvendo um problema usando um mapa de funções de ordem superior


 const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = birthYear.map(year => 2018 - year); //  [ 43, 21, 16, 23, 33 ] console.log(ages); 

▍ Método Array.prototype.filter


O método filter() cria, com base na matriz, uma nova matriz na qual caem os elementos da matriz original, correspondendo à condição especificada na função de retorno de chamada passada para esse método. Esta função leva, como no caso do método map() , 3 argumentos: element , index e array .

Considere um exemplo construído da mesma maneira que ao considerar o método map() .

Exemplo


Suponha que tenhamos uma matriz contendo objetos cujas propriedades armazenem informações sobre o nome e a idade dos representantes de um determinado grupo de pessoas. Precisamos criar uma matriz na qual haverá informações apenas sobre os representantes adultos deste grupo (aqueles cuja idade atingiu 18 anos).

Resolvendo um problema sem usar funções de ordem superior


 const persons = [ { name: 'Peter', age: 16 }, { name: 'Mark', age: 18 }, { name: 'John', age: 27 }, { name: 'Jane', age: 14 }, { name: 'Tony', age: 24}, ]; const fullAge = []; for(let i = 0; i < persons.length; i++) { if(persons[i].age >= 18) {   fullAge.push(persons[i]); } } console.log(fullAge); 

Resolvendo um problema usando um filtro de função de ordem superior


 const persons = [ { name: 'Peter', age: 16 }, { name: 'Mark', age: 18 }, { name: 'John', age: 27 }, { name: 'Jane', age: 14 }, { name: 'Tony', age: 24}, ]; const fullAge = persons.filter(person => person.age >= 18); console.log(fullAge); 

▍ Método Array.prototype.reduce


O método reduce() processa cada elemento da matriz usando um retorno de chamada e coloca o resultado em um único valor de saída. Este método usa dois parâmetros: retorno de chamada e valor inicial opcional ( initialValue ).

Um retorno de chamada aceita quatro parâmetros: accumulator (acumulador), currentValue (valor atual), currentIndex (índice atual), sourceArray (matriz de origem).

Se o parâmetro initialValue for fornecido ao initialValue , no início do método, o accumulator será igual a esse valor e o primeiro elemento da matriz processada será gravado em currentValue .

Se o parâmetro initialValue não for fornecido ao método, o primeiro elemento da matriz será gravado no accumulator e o segundo no currentValue .

Exemplo


Suponha que tenhamos uma matriz de números. Precisamos calcular a soma de seus elementos.

Resolvendo um problema sem usar funções de ordem superior


 const arr = [5, 7, 1, 8, 4]; let sum = 0; for(let i = 0; i < arr.length; i++) { sum = sum + arr[i]; } //  25 console.log(sum); 

Resolver um problema usando uma função de ordem superior reduz


Primeiro, considere usar o método reduce() sem fornecer um valor inicial.

 const arr = [5, 7, 1, 8, 4]; const sum = arr.reduce(function(accumulator, currentValue) { return accumulator + currentValue; }); //  25 console.log(sum); 

Cada vez que um retorno de chamada é chamado com um currentValue passado para currentValue , ou seja, o próximo elemento da matriz, seu parâmetro accumulator acaba contendo os resultados da operação anterior, ou seja, o que foi retornado da função na iteração anterior. Após a conclusão deste método, o resultado final cai na sum constante.

Agora, vamos ver como será a solução para o problema se passarmos o valor inicial para o método reduce() .

 const arr = [5, 7, 1, 8, 4]; const sum = arr.reduce(function(accumulator, currentValue) { return accumulator + currentValue; }, 10); //  35 console.log(sum); 

Como você pode ver, o uso de uma função de ordem superior tornou nosso código mais limpo, mais conciso e fácil de ler.

Crie funções personalizadas de ordem superior


Até o momento, trabalhamos com funções de ordem superior incorporadas ao JS. Agora vamos criar nossa própria função que funciona com outras funções.

Imagine que o JavaScript não possui um método padrão de matriz map() . Nós mesmos podemos criar esse método, que será expresso no desenvolvimento de uma função de ordem superior.

Suponha que tenhamos uma matriz de seqüências de caracteres e gostaríamos de criar em sua base uma matriz com números, cada um dos quais representa o comprimento da sequência armazenada em algum elemento da matriz original.

 const strArray = ['JavaScript', 'Python', 'PHP', 'Java', 'C']; function mapForEach(arr, fn) { const newArray = []; for(let i = 0; i < arr.length; i++) {   newArray.push(     fn(arr[i])   ); } return newArray; } const lenArray = mapForEach(strArray, function(item) { return item.length; }); //  [ 10, 6, 3, 4, 1 ] console.log(lenArray); 

Neste exemplo, criamos uma função de ordem superior mapForEach , que mapForEach uma matriz e uma função de retorno de chamada fn . A função mapForEach matriz em um loop e chama o retorno de chamada fn a cada iteração desse loop.

O retorno de chamada fn aceita o elemento de string atual da matriz e retorna o comprimento desse elemento. O que a função fn retorna é usado no comando newArray.push() e entra na matriz que mapForEach() retornará. Essa matriz será gravada na constante lenArray .

Sumário


Neste artigo, falamos sobre funções de ordem superior e exploramos algumas das funções internas do JavaScript. Além disso, descobrimos como criar suas próprias funções de ordem superior.

Em poucas palavras, pode-se dizer que a essência das funções de ordem superior são funções que podem assumir outras funções como argumentos e retornar outras funções como resultados de seu trabalho. Trabalhar com outras funções em funções de ordem superior parece o mesmo que trabalhar com outros objetos.

Caros leitores! Você precisa escrever suas próprias funções de ordem superior?

Source: https://habr.com/ru/post/pt428570/


All Articles