Muitas vezes precisamos realizar uma ação semelhante em muitos lugares do script.
Por exemplo, precisamos mostrar uma mensagem bonita quando um visitante faz login, sai e talvez em outro lugar.
As funções são os principais “blocos de construção” do programa. Eles permitem que o código seja chamado muitas vezes sem repetição.
Já vimos exemplos de funções integradas, como alert(message)
, prompt(message, default)
e confirm(question)
. Mas também podemos criar nossas próprias funções.
Para criar uma função podemos usar uma declaração de função .
Parece assim:
function showMessage() { alerta('Olá a todos!'); }
A palavra-chave function
vai primeiro, depois vem o nome da função , depois uma lista de parâmetros entre parênteses (separados por vírgulas, vazios no exemplo acima, veremos exemplos mais tarde) e por fim o código da função, também nomeado “o corpo da função”, entre chaves.
nome da função(parâmetro1, parâmetro2, ... parâmetroN) { // corpo }
Nossa nova função pode ser chamada pelo seu nome: showMessage()
.
Por exemplo:
function showMessage() { alerta('Olá a todos!'); } mostrarMensagem(); mostrarMensagem();
A chamada showMessage()
executa o código da função. Aqui veremos a mensagem duas vezes.
Este exemplo demonstra claramente um dos principais propósitos das funções: evitar a duplicação de código.
Se alguma vez precisarmos alterar a mensagem ou a forma como ela é mostrada, basta modificar o código em um só lugar: a função que a gera.
Uma variável declarada dentro de uma função só é visível dentro dessa função.
Por exemplo:
function showMessage() { deixe mensagem = "Olá, sou JavaScript!"; //variável local alerta(mensagem); } mostrarMensagem(); // Olá, sou JavaScript! alerta(mensagem); // <-- Erro! A variável é local para a função
Uma função também pode acessar uma variável externa, por exemplo:
deixe nome_do_usuário = 'João'; function showMessage() { deixe mensagem = 'Olá, ' + userName; alerta(mensagem); } mostrarMensagem(); // Olá, João
A função tem acesso total à variável externa. Ele também pode modificá-lo.
Por exemplo:
deixe nome_do_usuário = 'João'; function showMessage() { nome_do_usuário = "Bob"; // (1) alterou a variável externa deixe mensagem = 'Olá, ' + userName; alerta(mensagem); } alerta(nomeUsuário); //John antes da chamada da função mostrarMensagem(); alerta(nomeUsuário); // Bob, o valor foi modificado pela função
A variável externa só é usada se não houver uma variável local.
Se uma variável com o mesmo nome for declarada dentro da função, ela obscurece a externa. Por exemplo, no código abaixo a função usa o userName
local. O externo é ignorado:
deixe nome_do_usuário = 'João'; function showMessage() { deixe userName = "Bob"; //declara uma variável local deixe mensagem = 'Olá, ' + userName; //Bob alerta(mensagem); } // a função criará e usará seu próprio nome de usuário mostrarMensagem(); alerta(nomeUsuário); // John, inalterado, a função não acessou a variável externa
Variáveis globais
Variáveis declaradas fora de qualquer função, como o userName
externo no código acima, são chamadas global .
Variáveis globais são visíveis em qualquer função (a menos que sejam ocultadas por locais).
É uma boa prática minimizar o uso de variáveis globais. O código moderno tem poucos ou nenhum global. A maioria das variáveis reside em suas funções. Às vezes, porém, eles podem ser úteis para armazenar dados em nível de projeto.
Podemos passar dados arbitrários para funções usando parâmetros.
No exemplo abaixo, a função possui dois parâmetros: from
e text
.
function showMessage(from, text) { // parâmetros: from, text alerta(de + ': ' + texto); } showMessage('Ann', 'Olá!'); //Ann: Olá! (*) showMessage('Ann', "E aí?"); // Ann: O que foi? (**)
Quando a função é chamada nas linhas (*)
e (**)
, os valores fornecidos são copiados para variáveis locais from
e text
. Então a função os utiliza.
Aqui está mais um exemplo: temos uma variável from
e a passamos para a função. Atenção: a função muda from
, mas a mudança não é vista externamente, pois uma função sempre obtém uma cópia do valor:
function showMessage(de, texto) { de = '*' + de + '*'; // faz com que "from" pareça mais bonito alerta(de + ': ' + texto ); } deixe de = "Ann"; showMessage(from, "Olá"); // *Ann*: Olá // o valor de "from" é o mesmo, a função modificou uma cópia local alerta(de); //Ana
Quando um valor é passado como parâmetro de função, ele também é chamado de argumento .
Em outras palavras, para esclarecer esses termos:
Um parâmetro é a variável listada entre parênteses na declaração da função (é um termo de tempo de declaração).
Um argumento é o valor que é passado para a função quando ela é chamada (é um termo de tempo de chamada).
Declaramos funções listando seus parâmetros e depois as chamamos de argumentos de passagem.
No exemplo acima, pode-se dizer: “a função showMessage
é declarada com dois parâmetros, depois chamada com dois argumentos: from
e "Hello"
”.
Se uma função for chamada, mas um argumento não for fornecido, o valor correspondente se tornará undefined
.
Por exemplo, a função showMessage(from, text)
mencionada acima pode ser chamada com um único argumento:
showMessage("Ana");
Isso não é um erro. Tal chamada produziria "*Ann*: undefined"
. Como o valor do text
não é passado, ele se torna undefined
.
Podemos especificar o chamado valor “padrão” (para usar se omitido) para um parâmetro na declaração da função, usando =
:
function showMessage(from, text = "nenhum texto fornecido") { alerta(de + ": " + texto ); } showMessage("Ana"); // Ann: nenhum texto fornecido
Agora, se o parâmetro text
não for passado, ele obterá o valor "no text given"
.
O valor padrão também aparece se o parâmetro existir, mas é estritamente igual undefined
, assim:
showMessage("Ann", indefinido); // Ann: nenhum texto fornecido
Aqui, "no text given"
é uma string, mas pode ser uma expressão mais complexa, que só é avaliada e atribuída se o parâmetro estiver faltando. Então, isso também é possível:
function showMessage(de, texto = outraFunção()) { // anotherFunction() só é executado se nenhum texto for fornecido // seu resultado se torna o valor do texto }
Avaliação de parâmetros padrão
Em JavaScript, um parâmetro padrão é avaliado toda vez que a função é chamada sem o respectivo parâmetro.
No exemplo acima, anotherFunction()
não é chamado, se o parâmetro text
for fornecido.
Por outro lado, é chamado de forma independente sempre que falta text
.
Parâmetros padrão no código JavaScript antigo
Vários anos atrás, o JavaScript não suportava a sintaxe dos parâmetros padrão. Então as pessoas usaram outras maneiras de especificá-los.
Hoje em dia podemos encontrá-los em escritas antigas.
Por exemplo, uma verificação explícita para undefined
:
function showMessage(de, texto) { if (texto === indefinido) { text = 'nenhum texto fornecido'; } alerta(de + ": " + texto ); }
…Ou usando o ||
operador:
function showMessage(de, texto) { // Se o valor do texto for falso, atribua o valor padrão // isso assume que text == "" é o mesmo que nenhum texto texto = texto || 'nenhum texto fornecido'; ... }
Às vezes faz sentido atribuir valores padrão aos parâmetros posteriormente, após a declaração da função.
Podemos verificar se o parâmetro é passado durante a execução da função, comparando-o com undefined
:
function showMessage(texto) { // ... if (text === indefinido) { // se o parâmetro estiver faltando text = 'mensagem vazia'; } alerta(texto); } mostrarMensagem(); //mensagem vazia
…Ou poderíamos usar o ||
operador:
function showMessage(texto) { // se o texto for indefinido ou falso, defina-o como 'vazio' texto = texto || 'vazio'; ... }
Os mecanismos JavaScript modernos suportam o operador de coalescência nulo ??
, é melhor quando a maioria dos valores falsos, como 0
, devem ser considerados “normais”:
function showCount(contagem) { // se a contagem for indefinida ou nula, mostra "desconhecido" alerta(contagem ?? "desconhecido"); } mostrarContagem(0); //0 mostrarContagem(nulo); // desconhecido mostrarContagem(); // desconhecido
Uma função pode retornar um valor de volta ao código de chamada como resultado.
O exemplo mais simples seria uma função que soma dois valores:
função soma(a, b) { retornar a + b; } deixe resultado = soma (1, 2); alerta(resultado); //3
O return
da diretiva pode estar em qualquer lugar da função. Quando a execução chega lá, a função para e o valor é retornado ao código de chamada (atribuído ao result
acima).
Pode haver muitas ocorrências de return
em uma única função. Por exemplo:
function verificarIdade(idade) { if (idade >= 18) { retornar verdadeiro; } outro { return confirm('Você tem permissão de seus pais?'); } } deixe idade = prompt('Quantos anos você tem?', 18); if (verificar Idade(idade)) { alerta('Acesso concedido'); } outro { alerta('Acesso negado'); }
É possível usar return
sem valor. Isso faz com que a função seja encerrada imediatamente.
Por exemplo:
function mostrarFilme(idade) { if ( !checkIdade(idade) ) { retornar; } alert("Mostrando o filme"); // (*) // ... }
No código acima, se checkAge(age)
retornar false
, showMovie
não prosseguirá para alert
.
Uma função com return
vazio ou sem retorno retorna undefined
Se uma função não retornar um valor, é o mesmo que retornar undefined
:
function doNothing() { /* vazio */ } alert(doNothing() === indefinido); // verdadeiro
Um return
vazio também é o mesmo que return undefined
:
function doNothing() { retornar; } alert(doNothing() === indefinido); // verdadeiro
Nunca adicione uma nova linha entre return
e o valor
Para uma expressão longa in return
, pode ser tentador colocá-la em uma linha separada, como esta:
retornar (algum + longo + expressão + ou + qualquer coisa * f(a) + f(b))
Isso não funciona, porque o JavaScript assume ponto e vírgula após return
. Isso funcionará da mesma forma que:
retornar; (algum + longo + expressão + ou + qualquer coisa * f(a) + f(b))
Então, efetivamente se torna um retorno vazio.
Se quisermos que a expressão retornada passe por várias linhas, devemos iniciá-la na mesma linha que return
. Ou pelo menos coloque os parênteses de abertura da seguinte forma:
retornar ( algum + longo + expressão + ou + tanto faz * f(a) + f(b) )
E funcionará exatamente como esperamos.
Funções são ações. Portanto, o nome deles geralmente é um verbo. Deve ser breve, o mais preciso possível e descrever o que a função faz, para que alguém que leia o código tenha uma indicação do que a função faz.
É uma prática comum iniciar uma função com um prefixo verbal que descreve vagamente a ação. Deve haver um acordo dentro da equipe sobre o significado dos prefixos.
Por exemplo, funções que começam com "show"
geralmente mostram alguma coisa.
Função começando com…
"get…"
– retorna um valor,
"calc…"
– calcular algo,
"create…"
– criar algo,
"check…"
– verifica algo e retorna um booleano, etc.
Exemplos de tais nomes:
showMessage(..) // mostra uma mensagem getAge(..) // retorna a idade (obtém de alguma forma) calcSum(..) // calcula uma soma e retorna o resultado createForm(..) // cria um formulário (e geralmente o retorna) checkPermission(..) // verifica uma permissão, retorna verdadeiro/falso
Com os prefixos em vigor, uma olhada no nome de uma função permite entender que tipo de trabalho ela realiza e que tipo de valor ela retorna.
Uma função – uma ação
Uma função deve fazer exatamente o que seu nome sugere, nada mais.
Duas ações independentes geralmente merecem duas funções, mesmo que sejam normalmente chamadas em conjunto (nesse caso podemos fazer uma terceira função que chama essas duas).
Alguns exemplos de quebra desta regra:
getAge
– seria ruim se mostrasse um alert
com a idade (só deveria pegar).
createForm
– seria ruim se modificasse o documento, adicionando um formulário nele (deveria apenas criá-lo e retornar).
checkPermission
– seria ruim se exibisse a mensagem access granted/denied
(deveria apenas realizar a verificação e retornar o resultado).
Esses exemplos assumem significados comuns de prefixos. Você e sua equipe são livres para concordar com outros significados, mas geralmente eles não são muito diferentes. Em qualquer caso, você deve ter um bom entendimento do que significa um prefixo, o que uma função prefixada pode ou não fazer. Todas as funções com o mesmo prefixo devem obedecer às regras. E a equipe deve compartilhar o conhecimento.
Nomes de funções ultracurtas
As funções usadas com frequência às vezes têm nomes ultracurtos.
Por exemplo, a estrutura jQuery define uma função com $
. A biblioteca Lodash tem sua função principal chamada _
.
Estas são exceções. Geralmente os nomes das funções devem ser concisos e descritivos.
As funções devem ser curtas e fazer exatamente uma coisa. Se isso for grande, talvez valha a pena dividir a função em algumas funções menores. Às vezes, seguir esta regra pode não ser tão fácil, mas é definitivamente uma coisa boa.
Uma função separada não é apenas mais fácil de testar e depurar – sua própria existência é um ótimo comentário!
Por exemplo, compare as duas funções showPrimes(n)
abaixo. Cada um gera números primos até n
.
A primeira variante usa um rótulo:
função mostrarPrimes(n) { nextPrime: for (seja i = 2; i < n; i++) { for (seja j = 2; j < i; j++) { if (i % j == 0) continue nextPrime; } alerta(eu); //um primo } }
A segunda variante usa uma função adicional isPrime(n)
para testar a primalidade:
função mostrarPrimes(n) { for (seja i = 2; i < n; i++) { se (!isPrime(i)) continuar; alerta(eu); //um primo } } função éPrime(n) { for (seja i = 2; i < n; i++) { se (n% i == 0) retornar falso; } retornar verdadeiro; }
A segunda variante é mais fácil de entender, não é? Em vez do trecho de código, vemos o nome da ação ( isPrime
). Às vezes, as pessoas se referem a esse código como autodescritivo .
Assim, funções podem ser criadas mesmo que não pretendamos reutilizá-las. Eles estruturam o código e o tornam legível.
Uma declaração de função se parece com isto:
nome da função(parâmetros, delimitado, por, vírgula) { /* código */ }
Os valores passados para uma função como parâmetros são copiados para suas variáveis locais.
Uma função pode acessar variáveis externas. Mas funciona apenas de dentro para fora. O código fora da função não vê suas variáveis locais.
Uma função pode retornar um valor. Caso contrário, seu resultado será undefined
.
Para tornar o código limpo e fácil de entender, é recomendado usar principalmente variáveis e parâmetros locais na função, não variáveis externas.
É sempre mais fácil entender uma função que recebe parâmetros, trabalha com eles e retorna um resultado do que uma função que não recebe parâmetros, mas modifica variáveis externas como efeito colateral.
Nomenclatura de função:
Um nome deve descrever claramente o que a função faz. Quando vemos uma chamada de função no código, um bom nome nos dá instantaneamente uma compreensão do que ela faz e retorna.
Uma função é uma ação, portanto os nomes das funções geralmente são verbais.
Existem muitos prefixos de funções bem conhecidos, como create…
, show…
, get…
, check…
e assim por diante. Use-os para sugerir o que uma função faz.
As funções são os principais blocos de construção dos scripts. Agora que cobrimos o básico, podemos começar a criá-los e usá-los. Mas isso é apenas o começo do caminho. Voltaremos a eles muitas vezes, nos aprofundando em seus recursos avançados.
importância: 4
A função a seguir retorna true
se o parâmetro age
for maior que 18
.
Caso contrário, ele pede uma confirmação e retorna o resultado:
function verificarIdade(idade) { se (idade > 18) { retornar verdadeiro; } outro { // ... return confirm('Os pais permitiram?'); } }
A função funcionará de maneira diferente se else
for removido?
function verificarIdade(idade) { se (idade > 18) { retornar verdadeiro; } // ... return confirm('Os pais permitiram?'); }
Existe alguma diferença no comportamento dessas duas variantes?
Não há diferença!
Em ambos os casos, return confirm('Did parents allow you?')
é executado exatamente quando a condição if
é falsa.
importância: 4
A função a seguir retorna true
se o parâmetro age
for maior que 18
.
Caso contrário, pede uma confirmação e retorna o resultado.
function verificarIdade(idade) { se (idade > 18) { retornar verdadeiro; } outro { return confirm('Os pais permitiram?'); } }
Reescreva-o, para fazer o mesmo, mas sem if
, em uma única linha.
Faça duas variantes de checkAge
:
Usando um operador de ponto de interrogação ?
Usando OU ||
Usando um operador de ponto de interrogação '?'
:
function verificarIdade(idade) { retorno (idade > 18) ? true: confirm('Os pais permitiram?'); }
Usando OU ||
(a variante mais curta):
function verificarIdade(idade) { regresso (idade > 18) || confirm('Os pais permitiram?'); }
Observe que os parênteses em torno age > 18
não são obrigatórios aqui. Eles existem para melhor legibilidade.
importância: 1
Escreva uma função min(a,b)
que retorne o menor de dois números a
e b
.
Por exemplo:
min(2, 5) == 2 min(3, -1) == -1 min(1, 1) == 1
Uma solução usando if
:
função min(a, b) { se (a < b) { retornar um; } outro { retornarb; } }
Uma solução com um operador de ponto de interrogação '?'
:
função min(a, b) { retornar a < b ? uma:b; }
PS No caso de uma igualdade a == b
não importa o que retornar.
importância: 4
Escreva uma função pow(x,n)
que retorne x
na potência n
. Ou, em outras palavras, multiplica x
por si mesmo n
vezes e retorna o resultado.
pow(3, 2) = 3 * 3 = 9 pow(3, 3) = 3 * 3 * 3 = 27 pow(1, 100) = 1 * 1 * ...* 1 = 1
Crie uma página da web que solicite x
e n
e mostre o resultado de pow(x,n)
.
Execute a demonstração
PS Nesta tarefa, a função deve suportar apenas valores naturais de n
: inteiros acima de 1
.
função pow(x, n) { deixe resultado = x; for (seja i = 1; i < n; i++) { resultado *=x; } resultado de retorno; } deixe x = prompt("x?", ''); deixe n = prompt("n?", ''); se (n < 1) { alert(`Power ${n} não é suportado, use um número inteiro positivo`); } outro { alerta( pow(x, n) ); }