Em JavaScript, uma função não é uma “estrutura mágica de linguagem”, mas um tipo especial de valor.
A sintaxe que usamos antes é chamada de Declaração de Função :
function digaOi() { alerta("Olá"); }
Existe outra sintaxe para criar uma função chamada Expressão de Função .
Permite-nos criar uma nova função no meio de qualquer expressão.
Por exemplo:
deixe dizerOi = function() { alerta("Olá"); };
Aqui podemos ver uma variável sayHi
recebendo um valor, a nova função, criada como function() { alert("Hello"); }
.
Como a criação da função acontece no contexto da expressão de atribuição (ao lado direito de =
), esta é uma Function Expression .
Observe que não há nome após a palavra-chave function
. A omissão de um nome é permitida para expressões de função.
Aqui nós a atribuímos imediatamente à variável, então o significado desses exemplos de código é o mesmo: “crie uma função e coloque-a na variável sayHi
”.
Em situações mais avançadas, que veremos mais adiante, uma função pode ser criada e imediatamente chamada ou agendada para execução posterior, não sendo armazenada em lugar nenhum, permanecendo assim anônima.
Reiteramos: não importa como a função é criada, uma função é um valor. Ambos os exemplos acima armazenam uma função na variável sayHi
.
Podemos até imprimir esse valor usando alert
:
function digaOi() { alerta("Olá"); } alerta(digaOi); //mostra o código da função
Observe que a última linha não executa a função, porque não há parênteses depois de sayHi
. Existem linguagens de programação onde qualquer menção ao nome de uma função provoca sua execução, mas JavaScript não é assim.
Em JavaScript, uma função é um valor, então podemos tratá-la como um valor. O código acima mostra sua representação em string, que é o código fonte.
Certamente, uma função é um valor especial, no sentido de que podemos chamá-la como sayHi()
.
Mas ainda é um valor. Portanto, podemos trabalhar com isso como com outros tipos de valores.
Podemos copiar uma função para outra variável:
function digaOi() { // (1) criar alerta("Olá"); } deixe func = digaOi; // (2) copiar função(); // Olá // (3) execute a cópia (funciona)! digaOi(); // Olá // isso ainda funciona também (por que não funcionaria)
Aqui está o que acontece acima em detalhes:
A Declaração de Função (1)
cria a função e a coloca na variável chamada sayHi
.
A linha (2)
copia-o na variável func
. Observe novamente: não há parênteses depois de sayHi
. Se houvesse, então func = sayHi()
escreveria o resultado da chamada sayHi()
em func
, não a própria função sayHi
.
Agora a função pode ser chamada como sayHi()
e func()
.
Também poderíamos ter usado uma Expressão de Função para declarar sayHi
, na primeira linha:
deixe dizerOi = function() { // (1) criar alerta("Olá"); }; deixe func = digaOi; // ...
Tudo funcionaria da mesma forma.
Por que há um ponto e vírgula no final?
Você pode se perguntar por que as expressões de função têm ponto e vírgula ;
no final, mas as declarações de função não:
function digaOi() { // ... } deixe dizerOi = function() { // ... };
A resposta é simples: uma Expressão de Função é criada aqui como function(…) {…}
dentro da instrução de atribuição: let sayHi = …;
. O ponto e vírgula ;
é recomendado no final da instrução, não faz parte da sintaxe da função.
O ponto e vírgula estaria lá para uma atribuição mais simples, como let sayHi = 5;
, e também está lá para uma atribuição de função.
Vejamos mais exemplos de passagem de funções como valores e uso de expressões de função.
Escreveremos uma função ask(question, yes, no)
com três parâmetros:
question
Texto da pergunta
yes
Função a ser executada se a resposta for “Sim”
no
Função a ser executada se a resposta for “Não”
A função deve fazer a question
e, dependendo da resposta do usuário, chamar yes()
ou no()
:
function perguntar(pergunta, sim, não) { if (confirmar(pergunta)) sim() senão não(); } função mostrarOk() { alerta("Você concordou."); } function mostrarCancel() { alert("Você cancelou a execução."); } // uso: as funções showOk, showCancel são passadas como argumentos para perguntar pergunte("Você concorda?", showOk, showCancel);
Na prática, tais funções são bastante úteis. A principal diferença entre uma ask
da vida real e o exemplo acima é que as funções da vida real usam maneiras mais complexas de interagir com o usuário do que uma simples confirm
. No navegador, essas funções geralmente desenham uma janela de perguntas bonita. Mas isso é outra história.
Os argumentos showOk
e showCancel
do ask
são chamados de funções de retorno de chamada ou apenas retornos de chamada .
A ideia é passarmos uma função e esperarmos que ela seja “chamada de volta” mais tarde, se necessário. No nosso caso, showOk
se torna o retorno de chamada para resposta “sim” e showCancel
para resposta “não”.
Podemos usar Expressões de Função para escrever uma função equivalente e mais curta:
function perguntar(pergunta, sim, não) { if (confirmar(pergunta)) sim() senão não(); } perguntar( "Você concorda?", function() { alert("Você concordou."); }, function() { alert("Você cancelou a execução."); } );
Aqui, as funções são declaradas dentro da chamada ask(...)
. Eles não têm nome e por isso são chamados de anônimos . Tais funções não são acessíveis fora do ask
(porque não são atribuídas a variáveis), mas é exatamente isso que queremos aqui.
Esse código aparece em nossos scripts com muita naturalidade, dentro do espírito do JavaScript.
Uma função é um valor que representa uma “ação”
Valores regulares como strings ou números representam os dados .
Uma função pode ser percebida como uma ação .
Podemos passá-lo entre variáveis e executar quando quisermos.
Vamos formular as principais diferenças entre declarações e expressões de funções.
Primeiro, a sintaxe: como diferenciá-los no código.
Declaração de Função: uma função, declarada como uma instrução separada, no fluxo de código principal:
//Declaração de função função soma(a, b) { retornar a + b; }
Expressão de Função: uma função criada dentro de uma expressão ou dentro de outra construção de sintaxe. Aqui, a função é criada no lado direito da “expressão de atribuição” =
:
// Expressão da função deixe soma = função (a, b) { retornar a + b; };
A diferença mais sutil é quando uma função é criada pelo mecanismo JavaScript.
Uma Expressão de Função é criada quando a execução a atinge e só pode ser utilizada a partir desse momento.
Assim que o fluxo de execução passar para o lado direito da atribuição let sum = function…
– vamos lá, a função está criada e pode ser usada (atribuída, chamada, etc.) a partir de agora.
As declarações de função são diferentes.
Uma declaração de função pode ser chamada antes de ser definida.
Por exemplo, uma declaração de função global é visível em todo o script, não importa onde esteja.
Isso se deve a algoritmos internos. Quando o JavaScript se prepara para executar o script, ele primeiro procura declarações de função globais nele e cria as funções. Podemos pensar nisso como um “estágio de inicialização”.
E depois que todas as declarações de função forem processadas, o código será executado. Portanto, ele tem acesso a essas funções.
Por exemplo, isso funciona:
digaOi("João"); // Olá, João function digaOi(nome) { alerta( `Olá, ${nome}` ); }
A declaração de função sayHi
é criada quando o JavaScript está se preparando para iniciar o script e fica visível em todos os lugares dele.
…Se fosse uma expressão de função, não funcionaria:
digaOi("João"); //erro! let sayHi = function(name) { // (*) não há mais mágica alerta( `Olá, ${nome}` ); };
As expressões de função são criadas quando a execução as atinge. Isso aconteceria apenas na linha (*)
. Tarde demais.
Outra característica especial das Declarações de Função é o seu escopo de bloco.
No modo estrito, quando uma declaração de função está dentro de um bloco de código, ela fica visível em todos os lugares dentro desse bloco. Mas não fora disso.
Por exemplo, vamos imaginar que precisamos declarar uma função welcome()
dependendo da variável age
que obtemos durante a execução. E então planejamos usá-lo algum tempo depois.
Se usarmos Declaração de Função, não funcionará como esperado:
deixe idade = prompt("Qual é a sua idade?", 18); //declara condicionalmente uma função se (idade <18) { função bem-vinda() { alerta("Olá!"); } } outro { função bem-vinda() { alerta("Saudações!"); } } // ...usá-lo mais tarde Bem-vindo(); // Erro: boas-vindas não estão definidas
Isso ocorre porque uma Declaração de Função só é visível dentro do bloco de código em que reside.
Aqui está outro exemplo:
deixe idade = 16; // tome 16 como exemplo se (idade <18) { Bem-vindo(); // (executa) // | função bem-vinda() { // | alerta("Olá!"); // | A declaração de função está disponível } // | em todos os lugares do bloco onde é declarado // | Bem-vindo(); // / (executa) } outro { função bem-vinda() { alerta("Saudações!"); } } // Aqui estamos sem chaves, // então não podemos ver as declarações de função feitas dentro deles. Bem-vindo(); // Erro: boas-vindas não estão definidas
O que podemos fazer para tornar welcome
visíveis fora if
?
A abordagem correta seria usar uma Expressão de Função e atribuir welcome
à variável que é declarada fora do if
e tem a visibilidade adequada.
Este código funciona como pretendido:
deixe idade = prompt("Qual é a sua idade?", 18); deixe bem-vindo; se (idade <18) { bem vindo = função() { alerta("Olá!"); }; } outro { bem vindo = função() { alerta("Saudações!"); }; } Bem-vindo(); //ok agora
Ou poderíamos simplificar ainda mais usando um operador de ponto de interrogação ?
:
deixe idade = prompt("Qual é a sua idade?", 18); seja bem-vindo = (idade <18) ? function() { alerta("Olá!"); } : function() { alert("Saudações!"); }; Bem-vindo(); //ok agora
Quando escolher Declaração de Função versus Expressão de Função?
Como regra geral, quando precisamos declarar uma função, a primeira coisa a considerar é a sintaxe da Declaração da Função. Dá mais liberdade na organização do nosso código, pois podemos chamar tais funções antes de serem declaradas.
Isso também é melhor para a legibilidade, pois é mais fácil procurar function f(…) {…}
no código do que let f = function(…) {…};
. As declarações de função são mais “atraentes”.
…Mas se uma Declaração de Função não nos convém por algum motivo, ou se precisarmos de uma declaração condicional (acabamos de ver um exemplo), então a Expressão de Função deve ser usada.
Funções são valores. Eles podem ser atribuídos, copiados ou declarados em qualquer local do código.
Se a função for declarada como uma instrução separada no fluxo de código principal, isso é chamado de “Declaração de Função”.
Se a função for criada como parte de uma expressão, ela é chamada de “Expressão de Função”.
As declarações de função são processadas antes da execução do bloco de código. Eles são visíveis em todos os lugares do bloco.
As expressões de função são criadas quando o fluxo de execução as atinge.
Na maioria dos casos, quando precisamos declarar uma função, uma Declaração de Função é preferível, porque é visível antes da própria declaração. Isso nos dá mais flexibilidade na organização do código e geralmente é mais legível.
Portanto, devemos usar uma Expressão de Função somente quando uma Declaração de Função não for adequada para a tarefa. Vimos alguns exemplos disso neste capítulo e veremos mais no futuro.