ICC Turma D - UnB 2/04

Prática 11

1- Funções e procedimentos

1.1 - Terminologia

Para tornar o código fonte modular e reutilizável, programas e scripts podem fazer uso de funções. Funções podem ser pré-definidas ou definidas pelo programador. Quando são pré-definidas, fazem parte da linguagem, ou do interpretador ou compilador da linguagem. Quando são definidas pelo programador, precisam ser declaradas. Para aprendermos como um programador pode definir e usar novas funções em JavaScript, precisamos antes conhecer um pouco de terminologia na metalinguagem, necessária para explicar a sintaxe.

Um trecho de código fonte que faz uma função executar é dito uma chamada a esta função. Uma chamada a uma função é formada pelo identificador (nome) desta função seguido de um parêntesis. Podemos citar, como exemplo, chamadas à função pré-definida prompt . Todos os trechos de código que você já escreveu, contendo  prompt(___) (o tracejado preto aqui é metalinguagem), são chamdas à função prompt. Aquilo que vai no lugar do tracejado é chamado de argumento da chamada à função. Particularizando um exemplo, dizemos que

prompt('Qual é o tamanho da matriz?')

é uma chamada à função prompt com argumento 'Qual é o tamanho da matriz?'. Neste caso o argumento é um valor literal.

Além de "pré-definidas" ou "definidas pelo programador", outra classificação útil na metalinguagem para funções diz respeito à maneira como a função produz seus  resultados. Se os dados que a função poduz, ao ser chamada, são inseridos no lugar da chamada, dizemos que a função retorna valor. Se os dados produzidos são inseridos de outra forma, dizemos que a função não retorna valor. Pare melhor distinguir esses dois casos, dizemos que uma função que não retorna valor é um procedimento. Funções (que não são procedimentos) só podem ser chamadas em expressões, e procedimentos só podem ser chamados como comandos.

Assim, supondo-o correto, do trecho de código abaixo

n = Number(prompt('Digite um número')); //primeiro comando
if( NaN(n) )                            //segundo comando
{
    alert('dado inválido')
}
else
{
    // código que processa número n
};

podemos dizer:
Pré-definidas na linguagem geralmente são aquelas funções que seriam úteis aos mais variados programas. Dentre essas, certamente haverão funções para entrada ou saída de dados, que precisam interagir com o sistema operacional do ambiente onde o programa vai executar, sem as quais a linguagem não teria utilidade.  Além dessas, podemos citar funções matemáticas, como aquelas que conhecemos do estudo de matemática ou das teclas de calculadoras mais sofisticadas.

Nesse ponto, cabe lembrar outra classificação para funções também útil na metalinguagem. Quando a linguagem de programação usa ou se orienta pelo conceito de objetos, certas funções pré-definidas são destinadas a serem usadas apenas com determinado tipo de objeto (classe), devido à natureza da informação que recebe ou produz. Nesses casos, dizemos que a função é um método desse objeto, ou da sua classe. Como exemplos em JavaScript, podemos citar as funções trigonométricas e exponenciais, que são implementadas como métodos da classe Math, e o método .sort(), que serve para ordenar elementos de um objeto array.

Porém, haverá situações em que um determinado trecho de código pode ser útil em mais de um lugar no programa, ou em mais de um programa, que o autor da linguagem de programação não pode antecipar. Para esses casos, uma linguagem de programação estruturada -- como JavaScript -- permite que o programador defina suas próprias funções e procedimentos.

Para definir uma função ou procedimento em JavaScript, o programador deve usar uma declaração function, onde o trecho de código que constitui esta função é fornecida ao interpretador, juntamente com os meios de receber dados de entrada e produzir dados de saída. Quando o interpretador encontra uma declaração desse tipo, ele não faz nada a não ser armazenar o trecho de código correspondente em algum lugar de memória, associá-lo ao identificador (nome) da função, e tomar conhecimento do processo pelo qual esta função, quando chamada, ira receber e retornar dados.
 
Uma chamada a função definida pelo programador opera exatamente como uma chamada a função pré-definida exceto por um pequeno detalhe. A declaração de uma função definida pelo programador precisa ser processada antes de ser chamada. Isto significa, em metalinguagem, que, no fluxo de execução do código, a declaração tem que ser percorrida antes das chamadas. 

Em Javascript, o fluxo de execução dos scripts está imerso no fluxo de execução do código html que os envolve. Como o fluxo de execução do html é sempre linear, do começo ao fim, há uma maneira simples de se garantir que a declaração de uma função seja processada antes que qualquer script possa fazer chamadas a ela. Basta incluir a declaração da função em um script que abrigue apenas declarações, no cabeçalho do documento html ( ou seja, na extensão da diretiva <head>  </head> ), e anteriormente (na ordem escrita) a qualquer outro script (de evento ou de diretiva).

1.2 - Declaração de Funções

A sintaxe para declaração de função (obervando que preto é metalinguagem e vermelho é comentário ) é a seguinte:

function nome_da_função( lista_de_parametros )
{
    // cláusula (ou corpo) da função
}

O nome da função é um identificador. Portanto, deve seguir a regra de formação de identificadores:

A lista de parâmetros é uma lista de identificadores, separados por vírgula caso haja mais de um parâmetro (espaços em branco ao lado de vírgula são permitidos). Cada identificador nesta lista serve para declarar implicitamente uma variável que será conhecida apenas no corpo da função, destinada à entrada de dados para esta função.  Uma tal variável é dita parâmetro da função.

Quando a função é chamada a executar, em algum trecho de código onde o nome dela esteja 'visível', a lista de argumentos nesta chamada inicializa, automatica e internamente, os correspondentes parâmetros.  A função estará 'visível' quando a declaração desta função já tiver sido processada, durante a mesma interpretação do mesmo documento html.

Um argumento deve ser do mesmo tipo que o parâmetro correspondente. Isto significa que o argumento deve ser uma expressão de mesmo tipo que o do parâmetro correspondente. Como JavaScript não é fortemente tipada, o tipo do parâmetro decorre da lógica da função, podendo ser entendido das operações que o corpo da função executa com o parâmetro. Antes de vermos alguns exemplos, resta ainda explicar como incluir, no corpo da função, comando para que a mesma retorne dados que calculou. Ou seja, como fazer para que ela insira os dados de saída no ponto onde foi chamada. A sintaxe para isso não poderia ser mais simples e óbvia.

...
return( Expressão cujo valor é o dado a ser retornado pela função )
...

 Usa-se o procedimento pré-definido return para a função retornar o dado de saída e encerrar sua execução.

Se o trecho de código que constitui o corpo da função não contiver nenhum comando assim formado, ou se o fluxo de execução não" visitar" um tal comando, a função não retornará valor. Obviamente que, se o corpo da função contiver algum comando de seleção, pode conter mais de um tal comando (um em cada possível caminho de execução).

Afora o procedimento return, o código no corpo de uma função definida pelo usuário é como um script qualquer. Pode conter declarações de variáveis, de instâncias de objetos, chamadas a funções visíveis (inclusive a si mema), etc. Quando o corpo da função contém uma chamada a si mesma, dizemos que ela é uma função recursiva.

No mais, precisamos levar em conta que, ao introduzirmos declarações de função em um documento html, o contexto onde identificadores são associados a objetos e elementos do programa ganha mais detalhe. Tudo que for declarado dentro da declaração de uma função será visível apenas dentro do corpo desta função. Parâmetros e variáveis declaradas dentro de uma função são desconhecidos fora da função. Eles só existem em memória durate a execução a uma chamada à função. E como se "reencarnassem" a cada chamada.

A cada chamada à função, cada parâmetro é inicializado com o argumento correspondente, e cada declaração de variável é refeita, "morrendo" quando a chamada retorna (encerra a execução). Por isso, variáveis definidas internamente são chamadas de variáveis locais à função. Passamos agora a examinar exemplos, para melhor sedimentar os conceitos.

2- Práticas com funções definidas pelo programador

        2.1 função fatorial

Para sedimentarmos os conceitos da sessão anteiror, vamos examinar a declaração de uma função que calcula o fatorial de um número inteiro. Seguindo as sugestões acima, a declaração desta função poderia se inserir no documento html como abaixo.

<html>
<head><title>Pratica com funções</title>
<script language="javascript">

    function fatorial( num )
    {
        for( cont = num-1; cont > 1; cont-- )
        {
             num = num * cont;
       
};
        return( num )
    }
</script>
</head>
<body>
<h2><center>Calculo de Fatorial</center></h2>

....
 

</body></html>         


Exercicio 11.1

Sua tarefa neste exercício consite em completar o código do documento html acima de forma que um outro script no mesmo documento possa interagir com o usuário para

Oberve que, neste exemplo
Se voce não entender como esta função pode estar calculando o fatorial do argumento em uma chamada, precisa fazer o computador chines. O computador chines consiste em um interpretador da linguagem feito de lápis e papel. Escreva com lapis e papel a simulação da execução, anotando o valor de cada variável e parâmetro antes e depois da execução de cada comando, testando a condição de parada do comando de repetição a cada volta. Quando a lógica de um código correto não se faz transparente para um leittor humano, o computador chines é o último recurso que resta a esse leitor, para entendê-lo.


Exercicio 11.2

Reescreva a função fatorial acima, para torná-la recursiva. Para torná-la recursiva, o código deve traduzir a definição de fatorial que empregue uma chamda a ela mesma. Teste o tipo de problema que voce pode ter  (com memória, por exemplo), quando uma função recursiva é executada.

O comando de repetição acima, neste caso, será trocado por um comando contendo uma chamada da função a ela mesma, caso a condição de parada não tenha sido satisfeita. Na implementação recursiva de uma tal função, esta condição de parada deixa de controlar um comando de repetição, para controlar um comando de seleção

       2.2 Prática rumo ao trabalho 9 e à última prova

Temos que adequar o trabalho 8 ao corpo de uma função, para o trabalho 9. Como ainda não estamos precisando reusar código, a justificativa para esta prática será "limpar" o código fonte do documento html. Desta forma, os dados de entrada do trabalho (valor da prestação, taxa de juros, etc.) serão passados do formulário para os parâmetros de uma função, como argumentos de uma chamada a esta função. Esta função deve retornar a cadeia de caracteres a ser inserida no textarea. Tudo é feito com um comando de atribuição, que passa a constituir o único comando do script do evento corresponte ao clique no botão "calcular".

Da mesma forma, podemos "limpar" o código da prática 10.1, que cria lista de números primos, usando uma ou mais funções. Candidato óbvio para  passar para uma função, nesse problema, é o código que testa se um dado número é primo ou não..