Pular para o conteúdo principal

1.1.4 Funções Compostas

Identificamos em JavaScript alguns dos elementos que devem aparecer em qualquer linguagem de programação poderosa:

  • Números e operações aritméticas são dados primitivos e funções primitivas.
  • O aninhamento de combinações fornece um meio de combinar operações.
  • Declarações de constantes que associam nomes a valores fornecem um meio limitado de abstração.

Agora aprenderemos sobre as declarações de funções, uma técnica de abstração muito mais poderosa pela qual uma operação composta pode receber um nome e, em seguida, ser chamada de unidade.

Começamos examinando como expressar a ideia de "multiplicação ao quadrado" (squaring). Podemos dizer: "Para o quadrado perfeito de algo, retorna ele vezes ele mesmo". Isso é expresso em nossa linguagem como

Exemplo de Código
function square(x) {
  return x * x;
}

Podemos entender isso da seguinte forma:

function  square(      x   ) { return  x    *    x; }
// ^ ^ ^ ^ ^ ^ ^
// Para o quadrado de algo, retorna ele vezes ele mesmo.
// perfeito

Temos aqui uma função composta, que recebeu o nome square. A função representa a operação de multiplicação de algo por si mesmo. A coisa a ser multiplicada recebe um nome local, x, que desempenha o mesmo papel que um pronome na linguagem natural. A avaliação da declaração cria esta função composta e a associa ao nome square.1

A forma mais simples de declaração de uma função é

function nome(parâmetros) { return expressão; }

O nome é um símbolo a ser associado à definição da função no ambiente.2 Os parâmetros são os nomes usados no corpo da função para se referir aos argumentos correspondentes da função. Os parâmetros são agrupados entre parênteses e separados por vírgulas, pois estarão em uma aplicação da função que está sendo declarada. Na forma mais simples, o corpo de uma declaração de função é uma única instrução de retorno3, que consiste na palavra-chave return seguida pela expressão de retorno que produzirá o valor da aplicação da função, quando os parâmetros são substituídos pelos argumentos reais para os quais a função é aplicada. Como as declarações constantes e as declarações de expressão, as declarações de retorno terminam com um caractere de ponto e vírgula.

Tendo declarado square, agora podemos usá-lo em uma expressão de aplicação de função, que transformamos em uma instrução usando um caractere de ponto e vírgula:

Exemplo de Código
square(21);

441

As aplicações de função são – depois das combinações de operadores – o segundo tipo de combinação de expressões em expressões maiores que encontramos. A forma geral de uma aplicação de função é

expressão-função-expressão(expressões-argumento)

onde a expressão de função da aplicação especifica a função a ser aplicada às expressões-argumento separadas por vírgula. Para avaliar a aplicação de uma função, o interpretador segue um procedimento bastante semelhante ao procedimento para combinações de operadores descrito na seção 1.1.3.

  • Para avaliar uma aplicação de função, faça o seguinte:
    1. Avalie as subexpressões da aplicação, a saber, a expressão de função e as expressões de argumento.
    2. Aplique a função que é o valor da expressão de função aos valores das expressões de argumento.
Exemplo de Código
square(2 + 5);

49

Aqui, a expressão do argumento é ela própria uma expressão composta, a combinação de operadores 2 + 5.

Exemplo de Código
square(square(3));

81

É claro que as expressões de aplicação de função também podem servir como expressões de argumento.

Também podemos usar a square como um bloco de construção na definição de outras funções. Por exemplo, x² + y² pode ser expressada como

Exemplo de Código
square(x) + square(y)

Podemos facilmente declarar uma função sum_of_squares4 que, dados quaisquer dois números como argumentos, produz a soma de seus quadrados:

Exemplo de Código
function sum_of_squares(x, y) {
  return square(x) + square(y);
}
Exemplo de Código
sum_of_squares(3, 4);

25

Agora podemos usar sum_of_squares como um bloco de construção na construção de outras funções:

Exemplo de Código
function f(a) {
  return sum_of_squares(a + 1, a * 2);
}
Exemplo de Código
f(5);

136

Além de funções compostas, qualquer ambiente JavaScript fornece funções primitivas que estão embutidas no interpretador ou carregadas de bibliotecas. Além das funções primitivas fornecidas pelos operadores, o ambiente JavaScript usado neste livro inclui funções primitivas adicionais, como a função math_log, que calcula o logaritmo natural de seu argumento.5 Essas funções primitivas adicionais são usadas exatamente da mesma maneira que as funções compostas; avaliar a aplicação math_log(1) resulta no número 0. De fato, não se poderia dizer olhando para a definição de sum_of_squares dada acima se ``square` foi embutida no interpretador, carregado de uma biblioteca ou definido como uma função composta.


[1] Observe que há duas operações diferentes sendo combinadas aqui: estamos criando a função e estamos dando a ela o nome square. É possível, de fato importante, ser capaz de separar essas duas noções – criar funções sem nomeá-las e dar nomes a funções que já foram criadas. Veremos como fazer isso na seção 1.3.2.

[2] Ao longo deste livro, descreveremos a sintaxe geral das expressões usando símbolos em itálico – por exemplo, nome – para denotar os "slots" na expressão a ser preenchida quando tal expressão for realmente usada.

[3] De maneira mais geral, o corpo da função pode ser uma sequência de instruções. Nesse caso, o interpretador avalia cada instrução na sequência sucessivamente até que uma instrução de retorno determine o valor da aplicação da função.

[4] A maneira como os nomes de várias partes, como sum_of_squares, são escritos, afeta a legibilidade dos programas, e as comunidades de programação diferem nisso. De acordo com a convenção do JavaScript comum, chamada camel case, o nome seria sumOfSquares. A convenção usada neste livro é chamada de snake case e foi escolhida por sua maior semelhança com a convenção usada na versão Scheme deste livro, onde hífens desempenham o papel de nossos sublinhados.

[5] Nosso ambiente JavaScript inclui todas as funções e constantes do objeto Math do ECMAScript, sob os nomes math_…. Por exemplo, o Math.log do ECMAScript está disponível como math_log. A página da web do MIT Press para este livro inclui o pacote JavaScript sicp que fornece essas e todas as outras funções JavaScript consideradas primitivas no livro.