Funções em JavaScript: escopo e fechamentos

Aprenda a organizar código JavaScript em funções reutilizáveis. Escreva declarações de função, expressões de função e funções de seta; passe valores por meio de parâmetros, valores padrão e parâmetros rest; e retorne resultados com return. Preveja onde uma variável pode ser usada com escopos de bloco, de função e global, use fechamentos para dar memória própria às funções e passe funções para outras funções como funções de retorno para escrever código flexível de ordem superior.

BásicoAula 3 de 9 do curso Curso de Programação em JavaScript

O que você vai aprender

  1. Organize um trecho de código reutilizável como função, chame-o com argumentos e escolha entre uma declaração de função, uma expressão de função e uma função de seta.
    • Declarar uma função e chamá-la
      Defina uma função nomeada com a palavra-chave function, chame-a e explique por que funções tornam o código mais curto, claro e fácil de alterar.
    • Armazenar uma função em uma variável com uma expressão de função
      Trate funções como valores: crie uma expressão de função, atribua-a a uma variável e explique como ela difere de uma declaração em elevação e nomeação.
    • Escrever funções de seta
      Use a sintaxe curta de seta, saiba quando uma função de seta retorna um valor automaticamente e explique como ela difere de funções escritas com function.
  2. Planeje o que entra em uma função e o que sai dela: relacione argumentos a parâmetros, defina valores padrão, aceite qualquer quantidade de argumentos, retorne resultados e acompanhe como as chamadas são executadas umas dentro das outras.
    • Relacionar argumentos a parâmetros
      Explique como os valores de uma chamada chegam aos parâmetros da função, o que acontece quando há argumentos de menos ou de mais e quais dados de quem chama a função ela pode alterar.
    • Definir valores padrão e aceitar qualquer quantidade de argumentos
      Defina valores padrão para parâmetros, reúna qualquer quantidade de argumentos com um parâmetro rest e espalhe um vetor em argumentos separados.
    • Retornar resultados de uma função
      Retorne um valor com return, use o resultado no código seguinte e diferencie retornar um valor de imprimi-lo ou alterar algo fora da função.
    • Acompanhar chamadas de função pela pilha de chamadas
      Rastreie a ordem em que chamadas aninhadas são executadas e retornam, e escreva uma função recursiva simples com um caso base.
  3. Preveja onde uma variável fica visível aplicando as regras de escopo de bloco, de função e global e de funções escritas dentro de outras funções.
    • Distinguir escopo de bloco, escopo de função e escopo global
      Explique o escopo de uma variável declarada com let, const ou var e use variáveis locais para manter funções independentes umas das outras.
    • Prever a qual variável um nome se refere
      Siga a cadeia de escopos para encontrar a variável associada a um nome, reconheça o sombreamento e explique a elevação e a zona morta temporal.
  4. Explique como uma função mantém acesso às variáveis ao seu redor depois que a função externa termina e use isso para construir fábricas de funções e estado privado.
    • Explicar o que um fechamento mantém na memória
      Descreva como uma função mantém acesso às variáveis do escopo em que foi criada, mesmo depois que a função externa retorna.
    • Usar fechamentos para criar fábricas de funções e estado privado
      Construa fábricas de funções, mantenha dados privados acessíveis por funções e evite o erro clássico de fechamento em um laço.
  5. Use funções como valores: passe-as a outras funções como funções de retorno, use e escreva funções de ordem superior e construa novas funções a partir das existentes.
    • Passar uma função de retorno para uma função
      Passe uma função para outra como argumento, escreva funções que chamam uma função de retorno e passe a própria função em vez de seu resultado.
    • Usar e escrever funções de ordem superior
      Reconheça funções de ordem superior, use os métodos de vetor que recebem funções de retorno e escreva sua própria função que recebe uma função como entrada.
    • Construir novas funções a partir de funções existentes
      Escreva funções de ordem superior que envolvem, combinam ou preenchem antecipadamente argumentos de outras funções, usando fechamentos para manter na memória a função recebida.

Guia de estudo de Funções em JavaScript

5 capítulos

1

Definir e chamar funções de três formas

Funções transformam instruções repetidas em tarefas nomeadas. Você vai ler e escrever três formas comuns e decidir se uma linha cria uma função, armazena uma ou chama uma. Pequenas diferenças na sintaxe importam: uma declaração fica disponível antes de sua posição no código, enquanto uma expressão armazenada precisa ser inicializada primeiro, e o corpo de uma função de seta pode mudar se um resultado é retornado. Essas distinções preparam você para passar funções como valores comuns.

1.1 Declarar uma função e chamá-la

Uma função dá um nome a uma tarefa e armazena as instruções para executá-la. Defini-la não executa essas instruções. Uma chamada as executa, e outra chamada as executa novamente com novas entradas.

Escreva a definição

Uma declaração tem a palavra-chave function, um nome, parênteses para os parâmetros e chaves para o corpo:

function greet(name) {
  console.log("Hello, " + name + "!");
}

Aqui, name é um parâmetro: um nome local para a entrada fornecida por cada chamada. O corpo junta essa entrada ao texto ao redor e imprime o resultado. A chave de fechamento marca o fim da definição; a execução continua com a próxima instrução fora dela.

Uma função sem entradas ainda precisa de parênteses. Por exemplo, function sayHi() { console.log("Hi"); } define uma tarefa com uma lista de parâmetros vazia. As chaves pertencem à definição; os parênteses depois de um nome aparecem tanto em definições quanto em chamadas, com funções diferentes.

Execute a tarefa
greet("Amira");
greet("Li");

A primeira chamada atribui a name o valor "Amira" e imprime “Hello, Amira!”. A segunda inicia uma nova chamada com name igual a "Li" e imprime “Hello, Li!”. A definição é compartilhada; a entrada pertence à chamada individual.

greet sozinho se refere ao valor da função. Ele não executa o corpo. Essa distinção importa quando uma linha parece não fazer nada: sayHi; lê um valor de função e o descarta, enquanto sayHi(); imprime “Hi”.

Substitua instruções copiadas

Suponha que vários relatórios precisem de um cabeçalho cercado por linhas:

function printHeading(title) {
  console.log("-----");
  console.log(title);
  console.log("-----");
}

printHeading("Report");
printHeading("Totals");

A primeira chamada imprime uma linha, “Report” e outra linha. A segunda imprime a mesma moldura ao redor de “Totals”. Para alterar o estilo das linhas, edite as duas instruções que as imprimem nessa única definição. Sem a função, cada cabeçalho copiado precisaria de sua própria correção.

Escolha um nome que diga o que uma chamada faz. printHeading descreve uma ação; isValidEmail nomeia uma verificação de sim ou não. Use camelCase, com a primeira palavra em minúsculas e as palavras seguintes começando com maiúsculas. Se um nome proposto unir duas tarefas separadas com “e”, considere dar a cada tarefa sua própria função.

Leia código que chama uma declaração antes de sua posição

As declarações são preparadas antes da execução do código ao redor. Esse comportamento é chamado de elevação:

sayHi();
function sayHi() {
  console.log("Hi");
}

A chamada funciona dentro do escopo da declaração, embora a definição escrita venha depois. A elevação não faz o corpo ser executado antes; ela disponibiliza a função para uma chamada.

Verifique a escrita e o uso de maiúsculas e minúsculas quando uma chamada falhar. Greet() e greet() são nomes diferentes. Chamar uma greeet() não declarada gera um ReferenceError; omitir os parênteses da chamada pode falhar silenciosamente, pois apenas ler uma função existente é código válido.

Principais conclusões

  • Definir uma função armazena instruções; chamá-la as executa.
  • Chame com parênteses, mesmo quando não houver argumentos.
  • Uma declaração fica disponível antes de sua posição no código, dentro do mesmo escopo.
  • Dê nome a uma tarefa clara para que o código repetido tenha um único lugar de alteração.

1.2 Armazenar uma função em uma variável com uma expressão de função

Funções são valores. Você pode manter uma em uma variável, copiar sua referência, passá-la para outra função ou retorná-la. Uma expressão de função cria esse valor onde se espera uma expressão.

Armazene uma função
const square = function (n) {
  return n * n;
};

const answer = square(4);

A expressão depois de = cria uma função. A atribuição a armazena em square; a chamada posterior retorna 16. Essa instrução termina com ponto e vírgula, seguindo a convenção de formatação usada aqui.

A posição de function distingue as formas. Uma definição escrita como uma instrução independente, function square(n) { ... }, é uma declaração. Uma função escrita depois de = ou diretamente como argumento de uma chamada é uma expressão. Ambas as formas de função comum podem aceitar parâmetros e retornar valores.

Use const para uma variável que contém uma função quando seu valor deve permanecer o mesmo. Chamar square(5) é permitido; atribuir square = 5; gera um TypeError. A constante protege a variável contra substituição. Ela não impede chamadas repetidas.

Guarde uma função ou seu resultado
const sq = square;
const result = square(3);

sq se refere à mesma função que square. Chamar sq(3) retorna 9. result contém o número 9 retornado por uma chamada. Ele não pode ser chamado como função. typeof square e typeof sq são "function"; typeof result é "number".

Ler uma atribuição da direita para a esquerda ajuda: primeiro decida se o lado direito cria uma função, refere-se a uma função existente ou chama uma função. A variável à esquerda recebe esse valor. Copiar a referência não cria uma segunda implementação independente.

Aguarde a execução da atribuição

Uma declaração e uma expressão armazenada ficam disponíveis para chamada em momentos diferentes:

FormaAntes da definição ou atribuição escrita
function square(n) { return n * n; }Pode ser chamada dentro de seu escopo
const square = function (n) { return n * n; };Ler square gera um ReferenceError
var square = function (n) { return n * n; };square é undefined; chamá-la gera um TypeError

Com const ou let, o nome não pode ser usado antes da inicialização. Com var, o nome existe desde o início, mas o valor da função só é atribuído quando a execução chega à expressão. A elevação da variável não eleva a atribuição.

Dê um nome interno a uma expressão
const factorial = function fact(n) {
  return n <= 1 ? 1 : n * fact(n - 1);
};

O nome externo é factorial. O nome fact pertence ao interior da função e permite que ela chame a si mesma; o código externo não pode usar esse nome interno diretamente. O nome da expressão também pode facilitar a leitura de rastreamentos de pilha. Por exemplo, factorial(3) calcula 3 vezes 2 vezes 1 e retorna 6.

Declarações funcionam bem para as principais tarefas nomeadas em um script. Expressões se encaixam onde o código precisa de um valor de função, como em uma atribuição a variável ou em um argumento. Escolher uma expressão muda como o valor é criado e armazenado, não como os parênteses o chamam.

Principais conclusões

  • Uma expressão de função cria um valor de função dentro de outra expressão.
  • Atribuir square copia uma referência à função; atribuir square(3) armazena seu resultado.
  • Uma expressão de função armazenada em const só pode ser chamada após a inicialização.
  • Uma variável de função declarada com var contém undefined antes da execução de sua atribuição.
  • Uma expressão nomeada pode usar seu nome interno para chamar a si mesma.

1.3 Escrever funções de seta

Funções de seta são expressões de função com uma escrita mais curta. Seu comportamento de retorno depende do que vem depois da seta, então examine o corpo antes de decidir o que uma chamada produz.

Escolha a forma dos parâmetros
const sayHi = () => "hi";
const double = n => n * 2;
const add = (a, b) => a + b;

Sem parâmetros, são necessários parênteses vazios. Um parâmetro simples pode dispensar os parênteses. Dois ou mais exigem parênteses. Um parâmetro padrão ou rest também precisa de parênteses: (n = 1) => n * 2 e (...nums) => nums.length são válidos.

A seta separa as entradas do corpo. const double = n => n * 2; cria a função e a armazena; double(6) depois a chama e retorna 12. Como qualquer const que contém uma expressão de função, double não pode ser lida antes da execução de sua linha de inicialização.

Retorne uma expressão ou escreva um bloco
CorpoExemploResultado da chamada com 2 e 3
Expressão concisa(a, b) => a + b5
Bloco com return(a, b) => { return a + b; }5
Bloco sem return(a, b) => { a + b; }undefined

Um corpo conciso retorna sua expressão automaticamente. As chaves iniciam um bloco de instruções. Em um bloco, avaliar uma expressão não a envia de volta a quem chamou a função; escreva return explicitamente.

Use um bloco quando a tarefa precisar de etapas intermediárias:

const describe = (n) => {
  const kind = n % 2 === 0 ? "even" : "odd";
  return n + " is " + kind;
};

Para describe(7), a condição é falsa, então kind recebe "odd". O retorno junta o número e as palavras em “7 is odd”. Remover esse retorno manteria o cálculo local, mas entregaria undefined a quem chamou a função.

Retorne um literal de objeto

Um literal de objeto também usa chaves. Envolva-o em parênteses para que o analisador sintático o interprete como uma expressão:

const makePoint = (x, y) => ({ x: x, y: y });

makePoint(2, 5) retorna um objeto com x igual a 2 e y igual a 5. Sem os parênteses, a primeira chave inicia um bloco. A forma com uma propriedade, () => { value: 1 }, retorna undefined; a forma semelhante com duas propriedades separadas por vírgula gera um erro de sintaxe. Os parênteses mudam como o corpo é interpretado.

Conheça os limites da forma mais curta

Funções de seta não têm seus próprios this ou arguments e não podem ser chamadas com new para construir objetos. Para um cálculo simples que não usa this nem arguments, uma função de seta e uma expressão de função comum se comportam da mesma forma. Substituir todas as funções comuns por funções de seta pode alterar o código que depende desses recursos.

Funções de seta curtas são especialmente fáceis de ler como funções de retorno. [1, 2, 3].map(n => n * 10) passa uma função que retorna um elemento transformado, produzindo [10, 20, 30]. Alterá-la para n => { n * 10; } faz cada valor de retorno se perder silenciosamente.

Principais conclusões

  • Um corpo conciso de função de seta retorna sua expressão automaticamente.
  • Um corpo em bloco de função de seta precisa de return explícito para retornar um valor calculado.
  • Use parênteses em torno de um literal de objeto retornado por uma função de seta com corpo conciso.
  • Listas de parâmetros vazias, com vários parâmetros, com valor padrão ou com rest precisam de parênteses.
  • Funções de seta não têm seus próprios this ou arguments e não podem ser construtoras.
2

Passar valores para funções e obter resultados

Uma chamada de função tem uma parte de entrada e uma de saída. Relacione argumentos a parâmetros, trate entradas opcionais ou flexíveis e acompanhe o valor retornado a quem chamou a função. Você também vai distinguir alterações locais de alterações em um vetor compartilhado e acompanhar chamadas aninhadas enquanto seu trabalho pausa e recomeça. O mesmo modelo de chamada e retorno explica a recursão simples, em que várias chamadas de uma função aguardam o fim de chamadas menores.

2.1 Relacionar argumentos a parâmetros

Os parâmetros de uma função dão nomes aos valores fornecidos por uma chamada. Para rastrear uma chamada, primeiro associe as entradas pela posição e depois acompanhe as operações no corpo.

Relacione posições e tipos
function area(width, height) {
  return width * height;
}

area(4, 2.5);

width e height são parâmetros; 4 e 2,5 são argumentos. Durante essa chamada, width contém 4 e height contém 2,5, então o resultado é 10. Os nomes dos parâmetros não são associados aos nomes das variáveis de quem chama a função. Com divide(a, b), trocar divide(10, 2) por divide(2, 10) muda o resultado de 5 para 0,2.

JavaScript não exige uma quantidade específica de argumentos. area(4) deixa height como undefined; multiplicar por esse valor produz NaN. area(4, 2, 99) retorna 8 porque esse corpo não usa o terceiro argumento. Uma função pode coletar argumentos extras, mas argumentos extras não usados não causam um erro automático.

Os tipos também importam, mesmo quando a chamada é aceita. area("4", 2) retorna 8 porque a multiplicação converte o texto. Uma função de adição se comporta de forma diferente: add("4", 2) retorna “42” quando seu corpo é return a + b;. Se o texto representa um número, add(Number("4"), 2) retorna 6.

Reatribua um parâmetro local

Cada parâmetro é local à sua chamada. Atribuir um novo número a ele não reatribui a variável de quem chamou a função:

let score = 5;
function reset(s) {
  s = 0;
}
reset(score);

A chamada copia o valor 5 para s. A atribuição muda s para 0, e score permanece 5. Números, cadeias de caracteres e booleanos seguem essa regra de cópia de valor. O código externo não pode ler s diretamente; uma função aninhada pode manter acesso a ele por meio de um fechamento.

Altere um vetor por meio de uma referência copiada

Um valor de vetor é uma referência a um vetor. Passar esse valor copia a referência, então quem chamou a função e o parâmetro podem acessar o mesmo vetor:

const list = [1, 2];
function addItem(arr) {
  arr.push(3);
}
addItem(list);

list agora é [1, 2, 3]. A função não reatribuiu list; ela alterou o vetor que ambos os nomes acessam. Uma declaração const impede a substituição da referência armazenada, não a alteração do conteúdo do vetor.

Compare com uma reatribuição local:

function clearLocal(arr) {
  arr = [];
}
clearLocal(list);

Isso faz apenas arr apontar para um novo vetor vazio. list ainda acessa [1, 2, 3]. Pergunte-se se uma operação altera um vetor existente, como faz push, ou atribui um valor diferente a um nome, como faz =.

Retorne um novo vetor quando a entrada deve permanecer intacta
function withItem(arr, item) {
  return arr.concat(item);
}

withItem([1, 2], 3) produz [1, 2, 3] como um novo vetor. O vetor de entrada permanece [1, 2]. Isso torna a função útil quando quem a chama precisa tanto da lista antiga quanto da lista ampliada. Deixe claras pelo nome e pelo comportamento da função as alterações que ela pretende fazer na entrada, para que outras pessoas possam usá-la de forma previsível.

Principais conclusões

  • Argumentos são associados a parâmetros pela posição.
  • Um argumento ausente fornece undefined; argumentos extras não usados são permitidos.
  • Reatribuir um parâmetro não reatribui a variável de quem chamou a função.
  • Modificar um vetor por meio de um parâmetro altera o vetor compartilhado.
  • Retornar um novo vetor pode preservar a entrada.

2.2 Definir valores padrão e aceitar qualquer quantidade de argumentos

Valores padrão tornam uma entrada opcional; parâmetros rest permitem que uma chamada forneça muitas entradas. A sintaxe de espalhamento conecta um vetor existente a uma função que espera argumentos separados.

Aplique um valor padrão apenas para undefined
function greet(name = "friend") {
  return "Hello, " + name;
}

Tanto greet() quanto greet(undefined) retornam “Hello, friend”. greet(null) retorna “Hello, null”, e greet("") retorna “Hello, ”. Um valor padrão é aplicado para undefined, não para todo valor que parece vazio.

Valores padrão são avaliados quando uma chamada precisa deles. Eles podem usar parâmetros anteriores: function makeBox(width, height = width) { return width * height; } retorna 9 para makeBox(3) e 12 para makeBox(3, 4). O segundo argumento explícito substitui o valor padrão nessa chamada.

Coloque as entradas obrigatórias primeiro. Com function total(amount, rate = 0.25) { return amount + amount * rate; }, total(80) retorna 100 e total(80, 0.5) retorna 120. Inverter os parâmetros faria a chamada comum com a taxa padrão exigir total(undefined, 80).

Código antigo pode usar level = level || 50;. Isso também substitui 0, false e uma cadeia de caracteres vazia porque são valores avaliados como falsos. Um parâmetro padrão preserva esses valores: function setVolume(level = 50) { return level; } retorna 0 para setVolume(0) e 50 para setVolume(undefined).

Reúna argumentos com rest
function sum(...numbers) {
  let total = 0;
  for (const n of numbers) {
    total += n;
  }
  return total;
}

sum(1, 2, 3) coloca [1, 2, 3] em numbers e retorna 6. sum() fornece a ele um vetor vazio, então o laço não adiciona nada e retorna 0. Um parâmetro rest é um vetor verdadeiro, pronto para métodos de vetor ou iteração.

Uma entrada fixa pode vir antes de rest: em function log(label, ...values) { console.log(label, values); }, log("scores", 7, 9) atribui a label a cadeia “scores” e a values o vetor [7, 9]. Apenas um parâmetro rest é permitido, e ele deve vir por último; caso contrário, JavaScript não consegue atribuir os argumentos restantes sem ambiguidade usando essa sintaxe.

Expanda argumentos com espalhamento
Posição de ...FunçãoExemplo
Lista de parâmetros da definiçãoReunir argumentos restantesfunction sum(...numbers) { ... }
Lista de argumentos da chamadaExpandir elementos de um vetorsum(...values)

Math.max(...[3, 7, 2]) recebe três números e retorna 7. Math.max([3, 7, 2]) recebe um vetor e retorna NaN. Os três pontos são idênticos na página, mas a sintaxe ao redor indica qual função eles desempenham.

Funções comuns também têm um objeto arguments que contém os argumentos passados a elas. Ele é semelhante a um vetor, com entradas indexadas e um tamanho, mas não é um vetor verdadeiro e não tem seus próprios métodos map ou filter. Funções de seta não têm seu próprio arguments. Prefira um parâmetro rest em código novo que precise de uma lista flexível de entradas.

Principais conclusões

  • Valores padrão se aplicam a argumentos ausentes e a undefined explícito, preservando 0 e null.
  • Uma expressão de valor padrão é avaliada para cada chamada que precisa dela.
  • Um parâmetro rest reúne os argumentos restantes em um vetor e vem por último.
  • O espalhamento expande um vetor em argumentos separados de uma chamada.
  • O antigo objeto arguments é semelhante a um vetor; rest produz um vetor verdadeiro.

2.3 Retornar resultados de uma função

Um valor retornado é a saída que outro código recebe de uma chamada. A impressão pode mostrar o mesmo valor na tela, mas fornece um resultado diferente a quem chamou a função, a menos que ela também o retorne.

Use a chamada como valor
function double(n) {
  return n * 2;
}
const x = double(5) + 1;

double(5) retorna 10, então a atribuição é avaliada como 10 mais 1 e armazena 11. Uma chamada pode aparecer em qualquer lugar onde seja necessário um valor apropriado. double(double(3)) primeiro obtém 6 da chamada interna e depois retorna 12 da externa. Math.round(double(2.3)) dobra o valor para 4,6 e arredonda para 5.

return também encerra imediatamente a chamada atual. Uma cláusula de guarda trata um caso especial antes do trabalho principal:

function safeDivide(a, b) {
  if (b === 0) {
    return null;
  }
  return a / b;
}

safeDivide(6, 0) retorna null e nunca chega à divisão. safeDivide(6, 2) pula a cláusula de guarda e retorna 3. Coloque a condição antes da operação que ela protege.

Separe o retorno da exibição
function addLog(a, b) {
  console.log(a + b);
}

addLog(2, 3) imprime 5, mas seu valor de retorno é undefined. Consequentemente, addLog(2, 3) * 2 imprime 5 e é avaliado como NaN. Uma função que chega ao fim sem um retorno, ou executa apenas return;, retorna undefined. A exibição no console é um efeito colateral, não a saída numérica utilizável da chamada.

Se quem chama a função precisa de uma soma, escreva return a + b;. Depois, quem chama pode escolher entre imprimi-la, armazená-la ou usá-la em outro cálculo. Isso mantém as decisões de exibição fora de um cálculo reutilizável.

Mantenha a expressão retornada na mesma linha
function brokenAdd(a, b) {
  return
  a + b;
}

JavaScript encerra a instrução return na quebra de linha. A função retorna undefined; a expressão posterior nunca é alcançada. Para uma expressão longa, comece-a ou abra um parêntese na linha de return e continue abaixo.

Reúna vários resultados em um valor

Uma chamada retorna um valor, mas esse valor pode ser um vetor:

function minMax(nums) {
  return [Math.min(...nums), Math.max(...nums)];
}
const [low, high] = minMax([4, 9, 1]);

O vetor retornado é [1, 9]. A desestruturação atribui sua primeira entrada a low e a segunda a high. Ainda há um único valor retornado, que contém dois resultados úteis.

Uma função pura calcula sua saída a partir de seus argumentos e não altera nada fora de si. double é pura. Imprimir, atualizar uma variável externa e modificar um vetor de entrada são efeitos colaterais. Cálculos puros são fáceis de verificar com exemplos de entrada e saída; efeitos colaterais devem ficar em funções com nomes claros, onde o programa precisa de alterações visíveis.

Principais conclusões

  • return fornece o valor da chamada e encerra a chamada atual.
  • Apenas imprimir deixa o valor de retorno da função como undefined.
  • Comece a expressão retornada na linha de return.
  • Um único vetor retornado pode transportar vários resultados.
  • Funções puras dependem de seus argumentos e não fazem alterações externas.

2.4 Acompanhar chamadas de função pela pilha de chamadas

Quando uma função chama outra, a função que fez a chamada pausa até que essa chamada retorne. A pilha de chamadas registra o trabalho não concluído para que a execução possa continuar no lugar certo.

Adicione e remova quadros de chamada

Cada chamada ativa tem um quadro que contém seus parâmetros, variáveis locais e o ponto de retorno. Uma nova chamada vai para o topo da pilha; um retorno remove esse quadro do topo.

function square(n) {
  return n * n;
}
function sumOfSquares(a, b) {
  return square(a) + square(b);
}
sumOfSquares(3, 4);

Primeiro, sumOfSquares começa com a igual a 3 e b igual a 4. Ela chama square(3), que retorna 9 e termina. Depois, square(4) é executada e retorna 16. A adição pausada pode agora terminar como 9 mais 16, e sumOfSquares retorna 25. As duas chamadas de square não se sobrepõem nesse rastreamento.

Cada chamada recebe novos parâmetros e variáveis locais. Chamar a mesma função duas vezes não reutiliza o estado numérico local de uma chamada anterior. Mesmo quando uma função chama a si mesma, a nova chamada tem seu próprio quadro.

Reduza um problema com recursão

Uma função recursiva chama a si mesma. Um caso base termina sem outra chamada a si mesma; um caso recursivo dá um passo em direção a esse caso base.

function factorial(n) {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

Para entradas inteiras não negativas, isso multiplica os inteiros até chegar a 1. Rastreie factorial(4) em duas direções:

  1. factorial(4) espera por factorial(3).
  2. Essa chamada espera por factorial(2).
  3. Essa chamada espera por factorial(1).
  4. O caso base retorna 1.
  5. As chamadas em espera retornam 2, depois 6 e depois 24.

A multiplicação na chamada com n igual a 4 acontece depois que a chamada menor retorna. Seu próprio n permaneceu 4 enquanto ela esperava.

Um caso base precisa ser alcançável. Usar apenas n === 1 falha para uma entrada inicial de 0 se cada chamada recursiva subtrair 1: os valores se tornam negativos e nunca chegam a 1. n <= 1 cobre tanto 0 quanto 1. Sem um caminho de parada, chamadas repetidas esgotam a pilha. Chrome e Node.js informam “RangeError: Maximum call stack size exceeded”; o Firefox usa “InternalError: too much recursion”.

Reconheça uma cópia menor da mesma tarefa
function countItems(list) {
  let count = 0;
  for (const item of list) {
    if (Array.isArray(item)) {
      count += countItems(item);
    } else {
      count += 1;
    }
  }
  return count;
}

countItems([1, [2, 3], [4, [5]]]) retorna 5. Cada vetor aninhado faz a mesma pergunta de contagem para uma lista menor. Um laço também é adequado para um fatorial simples; a recursão é especialmente útil quando os próprios dados são aninhados.

Se uma chamada falhar, leia o rastreamento de pilha a partir da chamada mais recente no topo. As entradas seguintes mostram quais chamadas ainda não concluídas levaram até ela. Entradas repetidas para uma função podem revelar uma recursão que não parou.

Principais conclusões

  • A pilha de chamadas acompanha chamadas não concluídas; retornos removem o quadro mais recente.
  • Cada invocação tem seus próprios parâmetros e variáveis locais.
  • A recursão precisa de um caso de parada e de progresso em direção a ele.
  • Resultados recursivos retornam pelas chamadas em espera na ordem inversa.
  • Um rastreamento de pilha mostra a chamada que falhou e as chamadas que levaram a ela.
  • Dados aninhados podem conter instâncias menores da mesma tarefa.
3

Explicar onde uma variável pode ser usada

Nomes de variáveis têm significado dentro de escopos. Os limites dos blocos, os limites das funções e o lugar onde uma função é definida determinam quais declarações ela pode acessar. Você vai acompanhar esses limites para prever um valor ou erro e depois distinguir o sombreamento da atualização de uma variável externa. A elevação e a zona morta temporal explicam por que um nome pode ser registrado antes de a execução chegar à sua linha e ainda assim estar indisponível para uso.

3.1 Distinguir escopo de bloco, escopo de função e escopo global

O escopo de uma variável é a região onde seu nome pode ser usado. O escopo permite que funções mantenham seus dados de trabalho separados e ainda usem entradas e valores do código ao redor.

Delimite as declarações

let e const têm escopo de bloco. Um bloco é uma região dentro de chaves, como um corpo de if, um corpo de laço ou um corpo de função:

if (true) {
  const msg = "hi";
  console.log(msg);
}

A impressão funciona dentro do bloco. Adicionar console.log(msg); depois dele gera um ReferenceError porque esse código externo não consegue acessar a declaração. Outra declaração externa com o mesmo nome seria uma variável diferente.

Parâmetros e variáveis dentro de uma função são locais a ela. Em function f() { let temp = 1; }, o código externo não consegue ler temp. Duas funções podem ter, cada uma, um total local sem compartilhá-lo. Cada chamada começa com novas variáveis locais; uma função aninhada retornada pode preservar o acesso posteriormente por meio de um fechamento.

Leia declarações antigas com var
DeclaraçãoLimite
let ou const dentro de um blocoEsse bloco
var dentro de uma funçãoA função que o contém, mesmo quando escrito em um bloco interno
Declaração de nível superior em um script comumO escopo global do script
Declaração de nível superior em um móduloEsse módulo
function test() {
  if (true) {
    var x = 1;
  }
  return x;
}

test() retorna 1 porque var ignora o limite do if. Substituí-lo por let x = 1; faz o retorno falhar: o x do bloco não está disponível ali. Da mesma forma, for (let i = 0; i < 3; i++) {} mantém i dentro do laço, enquanto um var i permanece disponível na função ou no script que o contém após o laço e contém 3.

Procure para fora a partir da posição em que a função foi escrita

Escopos são aninhados. Uma função interna pode usar nomes nos escopos que a envolvem, mas o código externo não pode procurar nas variáveis locais de uma função interna. Isso é escopo léxico: o lugar onde o código é escrito determina os nomes disponíveis.

const level = "global";
function show() {
  return level;
}
function run() {
  const level = "local";
  return show();
}

run() retorna “global”. show foi definida fora de run, então o escopo que a envolve contém o level externo. Chamá-la de dentro de run não lhe dá acesso ao level local de quem a chamou.

Mantenha o estado compartilhado sob controle

Uma variável de nível superior em um script comum é global e pode ser acessada por funções desse script. Variáveis globais compartilhadas podem fazer tarefas independentes afetarem umas às outras; scripts na mesma página também podem entrar em conflito por causa de nomes. Passar entradas e retornar saídas mantém as dependências visíveis.

Declare toda variável. No modo estrito, count = 5; gera um ReferenceError se não houver uma declaração acessível. Sem o modo estrito, uma atribuição assim pode criar uma variável global acidental. Um script pode ativar o modo estrito com "use strict"; em seu início; módulos o ativam automaticamente. Prefira const para valores que não são reatribuídos e let quando a reatribuição for necessária.

Principais conclusões

  • let e const obedecem aos limites do bloco; var obedece ao limite da função que o contém.
  • Parâmetros de função e variáveis locais não estão disponíveis para o código externo.
  • O escopo léxico segue o lugar onde uma função é definida, não onde ela é chamada.
  • Variáveis de nível superior de um módulo pertencem ao módulo.
  • Declare nomes explicitamente para evitar atribuições globais acidentais.

3.2 Prever a qual variável um nome se refere

O mesmo nome pode aparecer em vários escopos. JavaScript encontra a declaração relevante procurando para fora a partir do código atual e parando na primeira correspondência.

Siga a cadeia de escopos
let x = 1;
function f() {
  let x = 2;
  return x;
}

f() retorna 2. A declaração local sombreia o x externo, então a busca para dentro de f. O valor externo permanece 1. Um parâmetro pode sombrear um nome da mesma maneira. Se nenhum escopo da cadeia declarar um nome, sua leitura gera um ReferenceError.

Uma atribuição não declara uma nova variável. Com let count = 0; function add() { count = count + 1; }, add encontra a declaração externa e a altera. Inserir let muda o significado: cria um novo nome local, que pode ocultar justamente o valor que você pretendia ler.

Separe o registro da inicialização

A elevação descreve como as declarações são registradas antes da execução de seu escopo. Seu comportamento antes da inicialização é diferente:

DeclaraçãoAntes de sua linha de inicialização
Declaração de funçãoSua função está disponível
varSeu valor é undefined
let ou constO acesso gera um ReferenceError

Por exemplo, console.log(a); var a = 5; imprime undefined. A atribuição de 5 ainda não aconteceu. Já console.log(b); let b = 5; falha. O intervalo em que o nome léxico existe, mas não pode ser acessado, é sua zona morta temporal, frequentemente abreviada como TDZ.

Rastreie o sombreamento antes de uma linha de declaração
let n = 10;
function f() {
  console.log(n);
  let n = 20;
}
f();

O n interno sombreia o externo em todo o corpo da função, inclusive antes da linha em que a declaração foi escrita. Em console.log(n), esse nome interno ainda está em sua TDZ, então a chamada gera um ReferenceError. JavaScript não ignora uma declaração local não inicializada para recorrer ao valor externo 10.

O mesmo problema aparece em let count = count + 1; dentro de add. O lado direito lê o novo count local antes de sua inicialização. Se a intenção for atualizar um contador externo, use uma atribuição sem uma nova declaração. Se a intenção for calcular um valor separado, dê a ele outro nome e leia explicitamente o contador externo.

Distinga reatribuição de mutação

let e const não podem declarar novamente o mesmo nome em um escopo; fazer isso gera um SyntaxError. Um escopo interno pode declarar seu próprio nome, o que é sombreamento. var permite declarações repetidas em seu escopo, tornando mais difícil perceber a reutilização acidental de nomes.

const impede a reatribuição de sua variável. Ele não congela um vetor:

const list = [];
list.push(1);

A referência armazenada em list permanece a mesma enquanto o vetor muda para [1]. list = []; tentaria substituir a referência armazenada e falharia.

Mantenha uma declaração no menor escopo que precisa dela. Nomes distintos para tarefas distintas reduzem a necessidade de acompanhar mentalmente o sombreamento, e inicializar antes do uso evita falhas na TDZ.

Principais conclusões

  • A busca de um nome para na declaração mais próxima que o envolve.
  • Uma declaração local sombreia um nome externo mesmo antes da inicialização.
  • var começa como undefined; let e const são inacessíveis em sua TDZ.
  • Uma atribuição atualiza uma vinculação existente; uma declaração cria uma vinculação.
  • const impede a reatribuição, mas o conteúdo de um vetor ainda pode mudar.
  • Uma nova declaração no mesmo escopo difere do sombreamento em um escopo aninhado.
4

Usar fechamentos para dar memória própria às funções

Uma função retornada pode manter acesso às variáveis ao redor de sua definição. Essa ligação preservada dá memória a um contador e permite que uma fábrica construa funções com configurações próprias. Você vai rastrear chamadas separadas de uma fábrica, estado compartilhado e alterações posteriores em variáveis capturadas e depois usar as mesmas regras para explicar funções criadas em um laço. O estado privado decorre do escopo léxico comum, mesmo depois que a chamada externa retorna.

4.1 Explicar o que um fechamento mantém na memória

Uma função mantém uma ligação com o escopo onde foi criada. A função e esse acesso preservado formam um fechamento. A ligação se torna especialmente útil quando uma função aninhada é retornada e chamada depois que sua chamada externa terminou.

Dê memória a uma função retornada
function makeCounter() {
  let count = 0;
  return function () {
    count = count + 1;
    return count;
  };
}
const counter = makeCounter();

A chamada de makeCounter cria count, cria uma função interna e retorna essa função. Ela ainda não executa o corpo interno. counter agora contém o valor da função. Sua primeira chamada altera o count preservado de 0 para 1 e retorna 1. Sua chamada seguinte altera a mesma variável para 2 e retorna 2.

O quadro de pilha da chamada externa terminou, mas a variável capturada permanece acessível. Uma variável local que não tem mais nenhum uso acessível pode ser liberada; aqui, a função interna que pode ser chamada ainda precisa dela. O acesso pelo fechamento permanece após um retorno sem tornar a variável global.

Crie memórias independentes com chamadas separadas
const a = makeCounter();
const b = makeCounter();
a();
a();
b();

Os resultados são 1, 2 e 1. Cada chamada da fábrica criou um count diferente. As duas funções retornadas por chamadas separadas têm o mesmo código, mas ambientes preservados diferentes.

Copiar uma referência a uma função retornada funciona de outra maneira. Se const alias = a;, então alias() usa o contador existente de a; não chama makeCounter nem cria outro ambiente.

Mantenha variáveis, não cópias fixas
let greeting = "Hi";
const say = () => greeting;
greeting = "Hello";

say() retorna “Hello”. O fechamento lê a variável quando é executado, então uma atualização posterior fica visível. Ele não armazena uma cópia fixa de “Hi” no momento da criação.

O código externo não pode acessar diretamente o count local, e counter.count é undefined. Apenas código com acesso a esse ambiente léxico pode lê-lo ou atualizá-lo. Chamar o contador de outra função não muda qual contador ele usa.

Compartilhe estado dentro de uma chamada externa
function makeWallet() {
  let balance = 0;
  return [
    function deposit(n) { balance += n; return balance; },
    function getBalance() { return balance; }
  ];
}
const [deposit, getBalance] = makeWallet();
deposit(50);
deposit(20);

getBalance() retorna 70 porque as duas funções retornadas foram criadas na mesma chamada e se referem ao mesmo balance. Outra chamada de makeWallet() cria um saldo separado.

Principais conclusões

  • Um fechamento mantém acesso ao escopo onde sua função foi criada.
  • Uma variável capturada pode continuar utilizável depois que sua chamada externa retorna.
  • Chamadas separadas de uma fábrica criam ambientes separados.
  • Fechamentos leem os valores atuais das variáveis, não cópias fixas do momento da criação.
  • Funções da mesma chamada externa podem compartilhar estado privado.

4.2 Usar fechamentos para criar fábricas de funções e estado privado

Uma fábrica de funções usa o acesso de um fechamento para criar funções com configurações ou estado próprios. Quem chama a fábrica fornece a configuração uma vez e depois usa a função retornada muitas vezes.

Configure uma função com um parâmetro
function makeMultiplier(factor) {
  return (n) => n * factor;
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);

double(5) retorna 10 e triple(5) retorna 15. Cada função de seta retornada mantém o factor de sua própria chamada da fábrica. A função externa configura o comportamento; a interna executa o trabalho repetido.

A forma compacta é const makeMultiplier = (factor) => (n) => n * factor;. Duas setas significam duas criações de função, não dois cálculos consecutivos sobre um número. makeMultiplier(4)(5) primeiro retorna uma função configurada com 4 e depois a chama com 5 para obter 20.

Aplique uma regra ao estado privado
function makeLimiter(max) {
  let used = 0;
  return function () {
    if (used >= max) {
      return false;
    }
    used = used + 1;
    return true;
  };
}
const tryLogin = makeLimiter(3);

As três primeiras chamadas retornam true e incrementam used. A quarta retorna false antes de incrementar. used é local à chamada da fábrica, então o código externo não pode redefini-la por esse nome. A função retornada controla quais alterações estão disponíveis. Outro limitador teria sua própria variável used e seu próprio máximo.

Analise funções criadas em laços
const fns = [];
for (var i = 0; i < 3; i++) {
  fns.push(() => i);
}

O laço cria três funções, mas apenas um var i. Após o laço, essa variável contém 3. Chamar qualquer função armazenada agora retorna 3 porque cada fechamento lê a mesma vinculação atual. Criar uma função não avalia seu corpo nem guarda uma cópia fixa do i atual.

Alterar o cabeçalho para let i = 0 dá ao laço uma vinculação separada para cada iteração. As funções armazenadas retornam então 0, 1 e 2. A mesma distinção explica a impressão adiada: uma função de retorno de setTimeout que lê var i depois do laço vê o valor final, enquanto a versão com let mantém o valor de cada iteração.

Reconheça uma expressão imediatamente invocada

Código antigo muitas vezes cria um escopo de função privado e o executa imediatamente:

(function () {
  var hidden = 1;
  console.log(hidden);
})();

Isso é uma expressão de função imediatamente invocada, ou IIFE. Os parênteses externos criam uma expressão de função; os parênteses finais a chamam. hidden pertence a essa função, mantendo-se fora do escopo global ao redor. É um padrão comum em código escrito antes das declarações com escopo de bloco e dos módulos.

O acesso preservado também afeta a memória. Um fechamento que pode ser chamado e precisa de um vetor grande mantém esses dados acessíveis. Quando a função e seus dados capturados deixam de estar acessíveis, eles podem ser liberados. Armazene fechamentos de longa duração de forma consciente quando sua memória fizer parte da tarefa.

Principais conclusões

  • Fábricas retornam funções configuradas por seus argumentos.
  • Variáveis privadas podem ser alteradas por meio das operações retornadas.
  • Fechamentos em laços com var compartilham uma vinculação; iterações com let recebem vinculações separadas.
  • Uma IIFE cria um escopo de função e o executa imediatamente.
  • Fechamentos acessíveis mantêm acessíveis os dados capturados de que precisam.
5

Passar funções para outras funções

Passar uma função permite que quem faz a chamada escolha parte do comportamento de outra função. Você vai examinar como as funções receptoras invocam funções de retorno, quais argumentos fornecem e como usam o resultado. Métodos de vetor conhecidos se tornam exemplos de padrões reutilizáveis de ordem superior. Por fim, funções retornadas vão envolver chamadas, conectar saídas a entradas ou manter argumentos selecionados prontos para uso posterior, combinando valores de função com acesso por fechamento.

5.1 Passar uma função de retorno para uma função

Uma função de retorno é uma função fornecida como argumento para que outra função a chame. Ela permite que a função receptora cuide da tarefa geral enquanto quem faz a chamada fornece uma ação ou teste específico.

Passe uma ação para um laço
function repeat(times, action) {
  for (let i = 0; i < times; i++) {
    action(i);
  }
}
repeat(3, (i) => console.log(i));

repeat controla o laço e escolhe os valores 0, 1 e 2. A função de seta determina o que fazer com cada valor: imprimi-lo. Cada action(i) chama a função fornecida com o número daquela iteração.

Você pode passar uma função existente ou escrever uma no ponto de uso. repeat(2, sayHi) passa a função nomeada. repeat(2, (i) => console.log("Round " + (i + 1))) imprime “Round 1” e “Round 2”. Uma função de retorno pode ignorar argumentos de que não precisa.

Passe o valor, sem chamar antes

repeat(3, sayHi()) avalia sayHi() ao preparar os argumentos. Se sayHi apenas imprime, seu valor de retorno é undefined, então repeat recebe esse valor como action. A chamada posterior de action(i) falha com um TypeError porque undefined não pode ser chamado.

Use repeat(3, sayHi) para passar a função. Se a chamada posterior precisar de argumentos escolhidos, passe uma função envoltória como () => sayHi() para que a chamada aconteça dentro do corpo da função de retorno. Criar uma função e invocá-la são etapas separadas.

Verifique quais argumentos a função receptora fornece

Funções de retorno de vetores muitas vezes recebem mais de um argumento: o elemento, o índice e o vetor inteiro. Passar uma função existente só é seguro quando essas entradas correspondem aos significados de seus parâmetros.

["1", "2", "3"].map(parseInt);

Isso retorna [1, NaN, NaN]. parseInt aceita um segundo argumento para a base numérica, então o índice do vetor altera seu comportamento. Use ["1", "2", "3"].map((s) => parseInt(s, 10)) para escolher explicitamente a base 10, ou .map(Number) para converter essas cadeias de caracteres.

Retorne uma resposta à função receptora
function countIf(arr, test) {
  let n = 0;
  for (const x of arr) {
    if (test(x)) {
      n++;
    }
  }
  return n;
}

countIf([3, 8, 12, 5], (x) => x > 4) retorna 3. A função de retorno responde a uma pergunta para cada item; countIf usa cada resposta para decidir se incrementa o contador. Compare com repeat, cujo laço ignora o valor de retorno da função de retorno. O código ou a documentação da função receptora informa tanto os argumentos quanto a função do resultado.

Funções de retorno podem ser executadas imediatamente ou mais tarde. repeat e os métodos de vetor as chamam de forma síncrona antes de retornar. setTimeout(sayHi, 2000) agenda uma para mais tarde enquanto o código seguinte continua imediatamente. Ser uma função de retorno descreve como uma função é fornecida, não quando ela deve ser executada.

Principais conclusões

  • Uma função de retorno é passada para que outra função a chame.
  • A função receptora controla os argumentos da função de retorno e se seu resultado é usado.
  • Adicionar os parênteses de chamada cedo demais pode passar um resultado em vez de uma função.
  • Argumentos de funções de retorno de vetores podem alterar o comportamento de uma função existente.
  • Funções de retorno podem ser síncronas ou adiadas.

5.2 Usar e escrever funções de ordem superior

Uma função de ordem superior recebe uma função, retorna uma função ou faz ambas as coisas. O valor de função fornece o comportamento, enquanto a função de ordem superior gerencia um padrão reutilizável.

Escreva o padrão uma vez
function myMap(arr, transform) {
  const result = [];
  for (const item of arr) {
    result.push(transform(item));
  }
  return result;
}

myMap([1, 2, 3], (n) => n * n) retorna [1, 4, 9]. O laço e a construção do vetor de saída permanecem os mesmos; a função de retorno decide como cada entrada muda. Um filtro correspondente adiciona um item apenas quando test(item) é avaliado como verdadeiro. Com [4, 7, 10, 3] e (n) => n % 2 === 0, esse padrão mantém [4, 10].

Escolha o contrato de função de retorno necessário
MétodoFunção da função de retornoResultado do método
mapRetornar cada valor transformadoUm novo vetor do mesmo tamanho
filterRetornar um valor avaliado como verdadeiro para os itens a manterUm novo vetor com os itens selecionados
findTestar se há um item correspondenteA primeira correspondência, ou undefined
forEachExecutar uma ação para cada itemundefined
reduceRetornar o próximo acumuladorO acumulador final

map, filter e find não modificam o vetor de entrada por si mesmos, mas as funções de retorno ainda podem modificá-lo. Retornar um novo vetor de um método não torna puras todas as funções de retorno fornecidas.

Transporte um resultado por uma redução
[5, 10, 15].reduce((total, n) => total + n, 0);

O acumulador inicial é 0. A função de retorno retorna 5 para o primeiro item, 15 para o segundo e 30 para o terceiro. Cada retorno se torna o total da chamada seguinte. O método retorna 30 após o último item. Um vetor vazio sem acumulador inicial faz reduce gerar um TypeError; um valor inicial explícito também define o resultado útil para uma entrada vazia.

Retornar vetores torna o encadeamento possível. [3, 8, 12, 5].filter((n) => n > 4).map((n) => n * 2) primeiro mantém [8, 12, 5] e depois o transforma em [16, 24, 10]. Leia a cadeia na ordem de execução, da esquerda para a direita.

Forneça uma regra de ordenação numérica

Sem um comparador, sort compara entradas como cadeias de caracteres. Portanto, [10, 9, 1].sort() produz [1, 10, 9]. Para ordem numérica crescente, use .sort((a, b) => a - b). Um retorno negativo coloca a primeiro, um retorno positivo coloca b primeiro e zero deixa o par equivalente para a ordenação. Ao contrário de map e filter, sort reorganiza seu vetor de entrada.

Verifique os valores retornados

[1, 2, 3].map((n) => { n * 2; }) produz [undefined, undefined, undefined] porque o bloco não tem retorno. Usar forEach para construir um novo resultado por atribuição também falha se você esperar que o próprio método retorne um vetor. Escolha map para transformação e forEach para ações cujas saídas coletadas não são necessárias.

Um método de ordem superior expressa claramente um padrão conhecido. Um laço simples continua útil quando o trabalho precisa de break ou não se encaixa no contrato do método.

Principais conclusões

  • Funções de ordem superior recebem funções, retornam funções ou fazem ambas as coisas.
  • map, filter e find usam os resultados das funções de retorno de maneiras diferentes.
  • forEach retorna undefined; reduce retorna o acumulador final.
  • Uma função de retorno de redução deve retornar o próximo acumulador.
  • A ordenação numérica precisa de um comparador e modifica o vetor original.
  • Um método que retorna um novo vetor ainda pode executar funções de retorno com efeitos colaterais.

5.3 Construir novas funções a partir de funções existentes

Uma função pode retornar uma nova função que mantém uma função existente na memória. Funções envoltórias, composição e aplicação parcial usam esse padrão para adaptar o comportamento sem copiar o corpo da função original.

Envolva uma chamada e preserve seu resultado
function logged(fn) {
  return (...args) => {
    console.log("Calling with", args);
    const result = fn(...args);
    console.log("Result", result);
    return result;
  };
}
const add = (a, b) => a + b;

logged(add) cria uma função que mantém add como fn. Chamar logged(add)(2, 3) reúne os argumentos, repassa-os para add, imprime o valor retornado e retorna 5. Rest reúne as entradas da função envoltória; o espalhamento as repassa. O retorno final mantém a saída disponível para cálculos posteriores.

Já logged(add(2, 3)) passa o número 5. Chamar essa função envoltória mais tarde tenta chamar 5 e gera um TypeError. Há duas etapas: configurar a função envoltória com uma função e depois chamar a função retornada com entradas.

Mantenha estado ao redor de uma operação
function once(fn) {
  let done = false;
  let result;
  return (...args) => {
    if (!done) {
      done = true;
      result = fn(...args);
    }
    return result;
  };
}

Para uma operação que retorna normalmente, a primeira chamada executa fn e armazena seu resultado. Chamadas posteriores retornam esse valor armazenado sem executar fn novamente, mesmo que seus argumentos sejam diferentes. O booleano registra se a operação foi executada; verificar se o resultado é avaliado como verdadeiro estaria errado quando um resultado válido fosse 0 ou false. Cada chamada de once cria seu próprio indicador e resultado armazenado.

Passe um resultado para outra função
const compose = (f, g) => (x) => f(g(x));
const addOne = (n) => n + 1;
const square = (n) => n * n;

compose(square, addOne)(3) executa addOne(3) primeiro e depois eleva 4 ao quadrado para retornar 16. compose(addOne, square)(3) primeiro eleva 3 ao quadrado e depois adiciona 1, retornando 10. A função mais próxima da entrada é executada primeiro, então a ordem dos argumentos de compose importa.

Fixe alguns argumentos antecipadamente
function partial(fn, ...fixed) {
  return (...rest) => fn(...fixed, ...rest);
}
const greetWith = (greeting, name) => greeting + ", " + name;
const hello = partial(greetWith, "Hello");

hello("Ana") chama greetWith("Hello", "Ana") e retorna “Hello, Ana”. Essa função auxiliar de aplicação parcial coloca os argumentos fixos primeiro e os argumentos posteriores depois; mudar essa ordem altera a chamada subjacente.

Principais conclusões

  • Uma função envoltória mantém uma função na memória e acrescenta comportamento ao redor de sua chamada.
  • Rest e espalhamento permitem que uma função envoltória repasse argumentos separados.
  • Retornar o resultado da função envolvida mantém esse resultado utilizável por quem a chamou.
  • Uma função envoltória de execução única mantém um indicador e o primeiro resultado na memória.
  • compose(f, g) aplica g antes de f.
  • A aplicação parcial fixa argumentos selecionados antes de chamadas posteriores.

Exercícios resolvidos de Funções em JavaScript

5 Lições Interativas

1

Criar, armazenar e chamar uma função

11 passos
Acompanhe uma saudação reutilizável por declarações, valores de função e corpos de funções de seta.
  1. 1
    IntroduçãoSepare a receita da chamada

    Uma função armazena instruções para que várias chamadas possam reutilizá-las. Sua definição descreve uma tarefa; uma chamada executa essa tarefa com entradas específicas.

    Acompanhe uma saudação em três formas: uma declaração, uma expressão armazenada em uma variável e uma função de seta. Observe dois detalhes conforme a sintaxe muda: quando a função fica disponível e se seu corpo retorna um valor.

  2. 2
    ExemploDefina uma saudação
    function greet(name) {
      console.log("Hello, " + name + "!");
    }
    

    A palavra-chave, o nome, a lista de parâmetros e o corpo formam uma declaração. Nada foi impresso ainda: a definição armazena as instruções.

    name é um parâmetro cujo valor virá de uma chamada. O corpo pode ser reutilizado porque descreve como construir a saudação sem escolher antecipadamente o nome de uma pessoa.

  3. 3
    ExemploExecute as instruções armazenadas
    greet("Amira");
    greet("Li");
    

    As chamadas imprimem “Hello, Amira!” e “Hello, Li!” em linhas separadas. Cada uma reinicia o mesmo corpo com sua própria entrada.

    A expressão greet sozinha é o valor da função. Os parênteses em greet("Li") solicitam sua execução. Mesmo uma função sem entradas precisa de parênteses na chamada, como em sayHi().

  4. 4
    DesafioPreveja a chamada antecipada

    O que é impresso quando este script é executado?

    show();
    function show() { console.log("Ready"); }
    

    ---reveal---

    Ele imprime “Ready” uma vez. A declaração passa por elevação dentro de seu escopo, então a função está disponível na primeira linha. A elevação não executa o corpo por si só: a chamada explícita show() o executa. Uma linha que contivesse apenas show; leria a função sem imprimir nada.

  5. 5
    ExplicaçãoMantenha a função como valor
    const square = function (n) {
      return n * n;
    };
    const alias = square;
    

    A expressão cria uma função, e square a armazena. A segunda atribuição copia sua referência para alias; ela não calcula um quadrado. Tanto square(3) quanto alias(3) retornam 9.

    Em comparação, const answer = square(3); chama a função e armazena o número retornado.

  6. 6
    DesafioLocalize a primeira falha

    Este script imprime 16?

    console.log(square(4));
    const square = function (n) { return n * n; };
    

    ---reveal---

    Não. Ler square antes de sua inicialização com const gera um ReferenceError. A atribuição não foi executada, então o valor de função da expressão está indisponível. Mova a chamada para baixo da atribuição ou use uma declaração de função se a função precisar estar disponível para chamada antes nesse escopo.

  7. 7
    ExemploUse uma função de seta concisa
    const square = (n) => n * n;
    const add = (a, b) => a + b;
    

    Um corpo conciso de função de seta retorna sua expressão, então square(4) retorna 16 e add(2, 3) retorna 5.

    Um parâmetro simples pode dispensar parênteses: n => n * n. Listas vazias, vários parâmetros, parâmetros padrão e parâmetros rest precisam deles. Funções de seta são expressões, então essas variáveis const ainda precisam ser inicializadas antes do uso.

  8. 8
    DesafioCorrija um resultado ausente

    Por que add(2, 3) retorna undefined, e que alteração faz com que retorne 5?

    const add = (a, b) => { a + b; };
    

    ---reveal---

    As chaves iniciam um bloco, então a expressão é avaliada, mas não retornada. Escreva (a, b) => { return a + b; } ou remova as chaves para usar (a, b) => a + b. Ambas as correções retornam a soma. Apenas adicionar um ponto e vírgula depois da atribuição não muda o comportamento de retorno do corpo.

  9. 9
    DicaRetorne uma expressão de objeto
    const makePoint = (x, y) => ({ x: x, y: y });
    

    Os parênteses fazem do literal de objeto uma expressão retornada pelo corpo conciso. Uma chave de abertura sem parênteses iniciaria um bloco.

    Funções de seta não têm seus próprios this ou arguments e não podem ser construtoras. A forma curta funciona bem para cálculos simples, mas essas diferenças importam ao converter outros tipos de função.

  10. 10
    DesafioAcompanhe uma função e seu segundo nome

    O que copy(5) retorna?

    const adjust = (n) => { return n + 2; };
    const copy = adjust;
    

    ---reveal---

    Retorna 7. O bloco da função de seta contém um retorno explícito, e copy contém a mesma função que pode ser chamada que adjust. A atribuição não chamou a função nem armazenou um resultado numérico. Substituir const copy = adjust; por const copy = adjust(5); armazenaria 7, que não pode ser chamado.

  11. 11
    RecapitulaçãoLeia a operação em cada linha

    Uma declaração cria uma tarefa nomeada que fica disponível desde o início de seu escopo. Uma expressão cria um valor de função quando a execução chega a ela. O corpo conciso de uma função de seta retorna automaticamente; seu corpo em bloco precisa de return.

    Ao rastrear o código, distinga uma definição de função, uma atribuição de referência e uma chamada. São operações diferentes, mesmo quando usam o mesmo nome.

2

Rastrear entradas, saídas e chamadas em espera

16 passos
Relacione argumentos, acompanhe valores retornados e resolva um cálculo recursivo curto na ordem inversa.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoAcompanhe o que entra e sai de uma chamada
  2. 2
    ExemploRelacione argumentos pela posição
  3. 3
    ExemploDistinga mutação de reatribuição
  4. 4
    DesafioPreserve a entrada original
  5. 5
    ExplicaçãoO valor padrão se aplica a undefined
  6. 6
    ExemploReúna e depois expanda
  7. 7
    DesafioUse um valor padrão com rest
  8. 8
    ExemploRetorne o número necessário a quem chama a função
  9. 9
    ExemploInterrompa um caminho com um retorno antecipado
  10. 10
    DesafioAvalie de dentro para fora
  11. 11
    ExemploLembre-se da chamada não concluída
  12. 12
    ExplicaçãoDê à recursão um caminho de parada
  13. 13
    ExemploResolva os produtos em espera
  14. 14
    DesafioCorrija um limite da recursão
  15. 15
    ConexãoLeia uma falha pela pilha
  16. 16
    RecapitulaçãoAcompanhe um valor por cada limite
3

Encontrar a declaração associada a um nome

10 passos
Rastreie limites de bloco, busca léxica e momento da inicialização.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoPergunte onde o nome pertence
  2. 2
    ExemploCompare limites de bloco e de função
  3. 3
    ExemploUse o local da definição
  4. 4
    DesafioRastreie um valor local e um externo
  5. 5
    ExplicaçãoPare na declaração mais próxima
  6. 6
    Ideia-chaveRegistrado não significa inicializado
  7. 7
    DesafioPreveja a leitura de um nome sombreado
  8. 8
    DicaSepare reatribuição de mutação
  9. 9
    DesafioCombine uma função de retorno com o momento da busca
  10. 10
    RecapitulaçãoRastreie o local antes do valor
4

Dar memória própria às funções retornadas

11 passos
Rastreie o estado compartilhado e independente de fechamentos e depois examine funções criadas dentro de um laço.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoMantenha acesso após um retorno
  2. 2
    ExemploCrie um contador sem chamá-lo
  3. 3
    ExemploAtualize a variável preservada
  4. 4
    DesafioCompare contadores independentes
  5. 5
    Ideia-chaveMantenha a vinculação, não uma cópia fixa
  6. 6
    ExemploCrie um cálculo configurado
  7. 7
    ExemploMantenha uma contagem privada de usos
  8. 8
    DesafioExplique três resultados iguais
  9. 9
    ConexãoReconheça o escopo privado em código antigo
  10. 10
    DesafioCompartilhe uma operação configurada
  11. 11
    RecapitulaçãoAcompanhe quantos ambientes existem
5

Passar comportamento e construir funções adaptadas

15 passos
Rastreie argumentos de funções de retorno, resultados de métodos de vetor e funções que retornam funções configuradas.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoDeixe uma função fornecer o comportamento variável
  2. 2
    ExemploChame a ação fornecida
  3. 3
    DesafioUse o resultado de uma função de retorno
  4. 4
    DicaExamine todos os argumentos da função de retorno
  5. 5
    ExemploEscreva um padrão de transformação
  6. 6
    ExplicaçãoEscolha a forma do resultado
  7. 7
    DesafioRastreie uma seleção e uma transformação
  8. 8
    Ideia-chaveDefina a ordem numérica de forma consciente
  9. 9
    ExemploEnvolva e repasse uma chamada
  10. 10
    ExplicaçãoMantenha na memória se uma chamada foi executada
  11. 11
    ExemploFaça a composição de dentro para fora
  12. 12
    ExemploFixe entradas antes da chamada posterior
  13. 13
    DesafioPasse uma função de retorno configurada
  14. 14
    DesafioCorrija um resultado perdido em uma função envoltória
  15. 15
    RecapitulaçãoVerifique as duas etapas do código de ordem superior

Questões de Funções em JavaScript

50 Questões de Prática em 5 conjuntos

Conjunto 1: Ler funções e acompanhar seus valores10 Questões de Prática

Questão 1 de 10

Dada function showLabel() { console.log("Ready"); }, qual instrução chama a função?
  1. "showLabel";
  2. showLabel();
  3. showLabel;
  4. const label = showLabel;
Mostrar respostaOcultar resposta
Resposta: B
showLabel(); invoca a função, então seu corpo imprime “Ready”. Ler showLabel sem parênteses apenas produz o valor da função; atribuir esse valor a outro nome também deixa o corpo sem execução. Os parênteses de chamada são necessários mesmo quando não há argumentos.

Questão 2 de 10

O que copy contém após este código?

const triple = function (n) { return n * 3; };
const copy = triple;
  1. O valor undefined até que copy seja chamada.
  2. Uma função separada com estado privado copiado.
  3. O número retornado pela chamada de triple(3).
  4. Uma referência à mesma função que triple.
Mostrar respostaOcultar resposta
Resposta: D
A atribuição lê o valor de função em triple e armazena a mesma referência em copy. Não há chamada no lado direito, então nenhum resultado numérico é calculado. Uma chamada posterior de copy(4) invocaria essa função e retornaria 12; copiar sua referência não a executa.

Questão 3 de 10

O que adjust(8) retorna?

const adjust = (n) => { n - 3; };
  1. undefined
  2. 5
  3. 8
  4. NaN
Mostrar respostaOcultar resposta
Resposta: A
As chaves fazem deste um corpo em bloco, e o bloco não tem return. Ele avalia a subtração, mas termina com undefined. O resultado seria 5 com um corpo conciso, (n) => n - 3, ou com um return n - 3; explícito dentro do bloco.

Questão 4 de 10

O que difference(12, 5) retorna?

function difference(first, second) {
  return first - second;
}
  1. 17
  2. undefined
  3. 7
  4. -7
Mostrar respostaOcultar resposta
Resposta: C
O primeiro argumento define first como 12, e o segundo define second como 5. Subtrair na ordem do corpo resulta em 7. O resultado -7 viria da inversão das posições dos argumentos; os nomes dos parâmetros não reorganizam os valores fornecidos pela chamada.

Questão 5 de 10

O que readLevel(0) retorna?

function readLevel(level = 40) { return level; }
  1. 40
  2. undefined
  3. null
  4. 0
Mostrar respostaOcultar resposta
Resposta: D
O argumento 0 é fornecido e não é undefined, então permanece 0. Um parâmetro padrão não substitui todo valor avaliado como falso. A expressão antiga level || 40 substituiria 0 por 40, mas essa é uma regra diferente da usada pelo valor padrão na definição.

Questão 6 de 10

Qual número é impresso e qual é o valor de result?

function displayTotal(a, b) { console.log(a + b); }
const result = displayTotal(6, 9);
  1. Imprime 15; result é 15.
  2. Imprime 15; result é undefined.
  3. Não imprime nada; result é 15.
  4. Imprime undefined; result é 15.
Mostrar respostaOcultar resposta
Resposta: B
O corpo imprime a soma, 15, como efeito colateral. Depois chega ao fim sem retornar um valor, então a atribuição armazena undefined. Ver um número no console não significa que a chamada retornou esse número; para isso, o corpo precisaria de return a + b;.

Questão 7 de 10

O que acontece quando getFlag() é chamada?

function getFlag() {
  if (true) { let flag = "on"; }
  return flag;
}
  1. Ela gera um ReferenceError.
  2. Ela gera um TypeError.
  3. Ela retorna o valor undefined.
  4. Ela retorna a cadeia “on”.
Mostrar respostaOcultar resposta
Resposta: A
A declaração let pertence ao bloco if. No retorno fora desse bloco, não existe uma declaração acessível de flag, então a leitura gera um ReferenceError. Substituir let por var daria à variável escopo de função e permitiria que essa função retornasse “on”.

Questão 8 de 10

Quais valores as duas chamadas retornam, em ordem?

function makeStep() {
  let value = 4;
  return () => { value += 2; return value; };
}
const step = makeStep();
step();
step();
  1. 4, 6
  2. 8, 10
  3. 6, 8
  4. 6, 6
Mostrar respostaOcultar resposta
Resposta: C
A fábrica cria uma vinculação value inicializada com 4. A função retornada mantém acesso a ela, então a primeira chamada a atualiza para 6 e a segunda atualiza a mesma vinculação para 8. O retorno da fábrica não redefine a variável capturada antes de cada chamada posterior.

Questão 9 de 10

Qual é a sequência completa dos valores impressos?

function deliver(action) { action(7); }
console.log("start");
deliver((n) => console.log(n));
console.log("end");
  1. "start", 7, "end"
  2. "start", undefined, "end"
  3. "start", "end", 7
  4. 7, "start", "end"
Mostrar respostaOcultar resposta
Resposta: A
deliver chama a função de seta fornecida imediatamente com 7, antes de retornar ao script ao redor. A saída é, portanto, “start”, 7 e depois “end”. Uma função de retorno não é necessariamente adiada; esta função receptora contém uma chamada direta comum e nenhuma operação de agendamento.

Questão 10 de 10

Qual é o valor final de result?

const values = [2, 7, 4, 9];
const result = values
  .filter((n) => n > 3)
  .map((n) => n - 1)
  .reduce((total, n) => total + n, 5);
  1. 27
  2. 22
  3. 17
  4. 21
Mostrar respostaOcultar resposta
Resposta: B
O filtro mantém [7, 4, 9], e o map o transforma em [6, 3, 8]. A redução a partir do valor inicial 5 resulta em 11, depois 14 e depois 22. Um resultado de 17 omite o acumulador inicial fornecido e soma apenas os elementos transformados, mudando o significado da chamada final.
Conjunto 2: Escolher entradas e rastrear o estado preservado10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

O que acontece quando read() é chamada?

let label = "outer";
function read() {
  return label;
  let label = "inner";
}
  1. Ela retorna a cadeia “inner”.
  2. Ela retorna a cadeia “outer”.
  3. Ela gera um ReferenceError.
  4. Ela retorna o valor undefined.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

O que a chamada final retorna?

let word = "first";
const read = () => word;
word = "second";
function run() {
  const word = "third";
  return read();
}
run();
  1. "second"
  2. undefined
  3. "first"
  4. "third"
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Qual vetor a expressão final produz?

const readers = [];
for (let i = 1; i <= 3; i++) {
  let value = i;
  readers.push(() => value);
  value += 10;
}
readers.map((read) => read());
  1. [13, 13, 13]
  2. [1, 2, 3]
  3. [14, 14, 14]
  4. [11, 12, 13]
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

O que acontece quando este script é executado?

announce();
function announce() { console.log("Open"); }
  1. Ele gera um ReferenceError.
  2. Ele imprime undefined uma vez.
  3. Ele imprime “Open” uma vez.
  4. Ele gera um TypeError.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Como uma função de seta pode retornar um objeto com uma propriedade value igual à sua entrada n?
  1. (n) => ({ value: n })
  2. (n) => { return; value: n; }
  3. (n) => (value = n)
  4. (n) => { value: n }
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

O que a chamada retorna?

function combine(first, ...rest) {
  return first + rest.length;
}
const values = [8, 2, 6];
combine(...values);
  1. 16
  2. 8
  3. 11
  4. 10
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

O que guarded(0) retorna?

function guarded(n) {
  if (n === 0) { return "empty"; }
  return "filled";
}
  1. "filled"
  2. "empty"
  3. ["empty", "filled"]
  4. undefined
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

O que totalDown(3) retorna?

function totalDown(n) {
  if (n === 0) { return 0; }
  return n + totalDown(n - 1);
}
  1. 0
  2. 6
  3. 9
  4. 3
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

O que acontece quando a última linha é executada?

function speak() { console.log("Hi"); }
function twice(action) { action(); action(); }
twice(speak());
  1. Ela imprime “Hi” uma vez e depois gera um TypeError.
  2. Ela gera um TypeError antes de imprimir algo.
  3. Ela imprime “Hi” duas vezes e depois retorna normalmente.
  4. Ela imprime “Hi” três vezes e depois retorna normalmente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Qual é o resultado final?

const compose = (f, g) => (x) => f(g(x));
const subtract = (n) => n - 2;
const triple = (n) => n * 3;
const first = compose(triple, subtract);
const second = compose(subtract, triple);
first(second(4));
  1. 18
  2. 28
  3. 24
  4. 30
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 3: Relacionar chamadas, escopo e funções de retorno10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Quais são os valores de values e first depois disso?

const values = [12, 3, 20];
const first = values.sort((a, b) => a - b)[0];
  1. values é [12, 3, 20]; first é 3.
  2. values é [3, 12, 20]; first é 3.
  3. values é [20, 12, 3]; first é 20.
  4. values é [12, 20, 3]; first é 12.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

O que as chamadas read(0) e read(9) retornam, em ordem?

function once(fn) {
  let done = false;
  let result;
  return (...args) => {
    if (!done) {
      done = true;
      result = fn(...args);
    }
    return result;
  };
}
const read = once((n) => n * 2);
  1. undefined, 18
  2. 0, 18
  3. 0, 0
  4. 0, undefined
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

O que acontece quando este script é executado?

const saved = build;
const build = function () { return 9; };
console.log(saved());
  1. Ele gera um ReferenceError na primeira linha.
  2. Ele gera um TypeError na última linha.
  3. Ele imprime undefined na última linha.
  4. Ele imprime 9 após a conclusão da atribuição.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Qual valor é atribuído a out?

const describe = (n) => {
  const doubled = n * 2;
  return doubled + 1;
};
const out = describe(6);
  1. undefined
  2. 7
  3. 13
  4. 12
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Quais são os valores de items e answer após este código?

const items = [5];
function change(list) {
  list.push(8);
  list = [1];
  return list;
}
const answer = change(items);
  1. items é [5, 8]; answer é [5, 8].
  2. items é [5]; answer é [1].
  3. items é [1]; answer é [1].
  4. items é [5, 8]; answer é [1].
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

O que countLeaves([0, [[], 2], [[3], 4]]) retorna?

function countLeaves(list) {
  let count = 0;
  for (const item of list) {
    if (Array.isArray(item)) {
      count += countLeaves(item);
    } else {
      count++;
    }
  }
  return count;
}
  1. 6
  2. 4
  3. 3
  4. 5
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

O que readValue() retorna?

function readValue() {
  if (true) { var value = 14; }
  return value;
}
  1. 14
  2. undefined
  3. Ela gera um ReferenceError.
  4. Ela gera um TypeError.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Quais são os dois valores impressos?

let count = 2;
function update() {
  let count = 7;
  count += 1;
  return count;
}
console.log(update());
console.log(count);
  1. 3, 3
  2. 7, 2
  3. 8, 2
  4. 8, 8
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Quais valores as três últimas chamadas retornam?

function makeCounter(start) {
  let n = start;
  return () => { n++; return n; };
}
const a = makeCounter(5);
const alias = a;
const b = makeCounter(5);
a();
alias();
b();
  1. 5, 6, 5
  2. 6, 7, 6
  3. 6, 7, 8
  4. 6, 6, 6
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

O que scale(7) retorna?

const makeScale = (factor) => (n) => n * factor;
const scale = makeScale(4);
  1. 7
  2. 11
  3. Uma nova função.
  4. 28
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 4: Analisar o comportamento de funções em pequenos programas10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um script define function printLine() { console.log("---"); } e depois executa printline();. O que acontece?
  1. A chamada retorna undefined sem imprimir.
  2. Uma linha é impressa e a execução continua.
  3. Ocorre um TypeError e nenhuma linha é impressa.
  4. Ocorre um ReferenceError e nenhuma linha é impressa.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

O que a chamada final retorna?

const climb = function step(n) {
  return n === 0 ? 0 : 1 + step(n - 1);
};
const saved = climb;
saved(2);
  1. 0
  2. 2
  3. Ela gera um ReferenceError.
  4. 1
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Quais são os valores de data e result ao final?

const data = [2, 5];
function extend(list, item) {
  const next = list.concat(item);
  list.push(9);
  return next;
}
const result = extend(data, 7);
result.push(1);
  1. data é [2, 5, 9]; result é [2, 5, 7, 1].
  2. data é [2, 5, 9, 1]; result é [2, 5, 7, 1].
  3. data é [2, 5, 7, 9]; result é [2, 5, 7, 9, 1].
  4. data é [2, 5]; result é [2, 5, 7, 9, 1].
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

O que a chamada final retorna?

function total(base = 4, ...extras) {
  return extras.reduce((sum, n) => sum + n, base);
}
const values = [undefined, 3, 0, 8];
total(...values);
  1. NaN
  2. 11
  3. 15
  4. 19
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Qual valor esta chamada produz?

function read() {
  return;
}
read();
  1. undefined
  2. null
  3. false
  4. 0
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

A entrada n é um inteiro não negativo. Qual substituição para o retorno recursivo faz a função contar corretamente até 0 tanto para entradas ímpares quanto pares?

function countDown(n) {
  if (n === 0) { return 0; }
  // recursive return goes here
}
  1. return 1 + countDown(n - 2);
  2. return 1 + countDown(n - 1);
  3. return 1 + countDown(n);
  4. return 1 + countDown(n + 1);
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

O que a chamada final retorna?

const mode = "shared";
function readMode() { return mode; }
function run() {
  const mode = "local";
  return readMode();
}
run();
  1. Ela gera um ReferenceError.
  2. undefined
  3. "local"
  4. "shared"
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Quais valores jobs[0]() e jobs[1]() retornam após o laço?

const jobs = [];
for (var i = 0; i < 2; i++) {
  const offset = i * 10;
  jobs.push(() => offset + i);
}
  1. 12, 12
  2. 0, 10
  3. 2, 12
  4. 0, 11
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Qual resultado esta expressão produz?

["6", "8", "10"].map((text) => parseInt(text, 10));
  1. [6, NaN, NaN]
  2. [6, 8, 10]
  3. [6, NaN, 2]
  4. ["6", "8", "10"]
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Quais são os valores impressos de out e seen?

let seen = 0;
const out = [3, 5].forEach((n) => {
  seen += n;
  return n * 2;
});
console.log(out, seen);
  1. undefined, 8
  2. [6, 10], 8
  3. undefined, 16
  4. [6, 10], 0
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 5: Combinar fechamentos e funções de ordem superior10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

O que acontece quando build() é chamada?

let amount = 6;
function build() {
  const read = () => amount;
  const result = read();
  let amount = 9;
  return result;
}
  1. Ela retorna o número 6.
  2. Ela retorna o número 9.
  3. Ela retorna o valor undefined.
  4. Ela gera um ReferenceError dentro de read.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Quais valores change(3), read() e otherRead() retornam?

function makePair() {
  let n = 1;
  return [
    (step) => { n += step; return n; },
    () => n
  ];
}
const [change, read] = makePair();
const [, otherRead] = makePair();
  1. 4, 1, 1
  2. 4, 4, 4
  3. 3, 3, 1
  4. 4, 4, 1
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

O que a expressão final retorna?

function makeLimit(max) {
  let used = 0;
  return () => {
    if (used >= max) { return false; }
    used++;
    return true;
  };
}
const allow = makeLimit(2);
[allow(), allow(), allow()];
  1. [true, true, true]
  2. [true, true, false]
  3. [true, false, false]
  4. [false, false, false]
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Qual função de seta retorna a soma de suas duas entradas?
  1. (a, b) => { console.log(a + b); }
  2. (a, b) => { return a + b; }
  3. (a, b) => { return; a + b; }
  4. (a, b) => { a + b; }
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Qual é o resultado de add("6", 4) * 2?

function add(a, b) { return a + b; }
  1. 20
  2. NaN
  3. 128
  4. "6464"
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Qual é o resultado da expressão final?

function choose(n) {
  if (n < 0) { return 0; }
  return n + 2;
}
choose(choose(-4));
  1. 2
  2. -2
  3. 0
  4. 4
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Quais são os valores de result e calls após este código?

let calls = 0;
function choose(values, test) {
  for (const value of values) {
    calls++;
    if (test(value)) { return value; }
  }
  return null;
}
const result = choose([3, 8, 10, 5], (n) => n > 6 && n % 2 === 0);
  1. result é 8; calls é 2.
  2. result é [8, 10]; calls é 4.
  3. result é 8; calls é 4.
  4. result é 10; calls é 3.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Quais são os valores de items e out depois disso?

const items = [2, 4, 6];
const out = items.map((n, index, array) => {
  array[index] = n + 1;
  return n * 2;
});
  1. items é [4, 8, 12]; out é [3, 5, 7].
  2. items é [3, 5, 7]; out é [6, 10, 14].
  3. items é [3, 5, 7]; out é [4, 8, 12].
  4. items é [2, 4, 6]; out é [4, 8, 12].
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

O que doubleSaved(9) retorna após a chamada anterior mostrada?

function once(fn) {
  let done = false;
  let saved;
  return (...args) => {
    if (!done) { done = true; saved = fn(...args); }
    return saved;
  };
}
const compose = (f, g) => (x) => f(g(x));
const saved = once((n) => n + 3);
const doubleSaved = compose((n) => n * 2, saved);
saved(4);
doubleSaved(9);
  1. 18
  2. 14
  3. 7
  4. 24
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Qual é o vetor retornado?

const partial = (fn, ...fixed) => (...later) => fn(...fixed, ...later);
const offset = (base, n) => base + n;
const addFive = partial(offset, 5);
const compose = (f, g) => (x) => f(g(x));
const transform = compose((n) => n * n, addFive);
[1, 3].map(transform);
  1. [12, 16]
  2. [6, 14]
  3. [36, 64]
  4. [26, 28]
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Travou em uma questão sua? Ajuda com Tarefas

Termos-Chave

66 Termos-Chave, cada um com sua definição

A

Acumulador
Um acumulador é o resultado acumulado em uma redução, passado à função de retorno e substituído pelo valor retornado por ela a cada etapa.
Uma redução de soma que começa em 0 atualiza seu acumulador para 5, 15 e 30 ao processar [5, 10, 15].
Aplicação parcial
A aplicação parcial fixa argumentos selecionados antecipadamente e retorna uma função que fornece as entradas restantes quando chamada mais tarde.
Uma função de saudação parcialmente aplicada a “Hello” pode depois aceitar “Ana” e retornar “Hello, Ana”.
Argumento
Um argumento é um valor fornecido a uma chamada de função, associado pela posição a um parâmetro ou coletado entre as entradas restantes.
Em area(4, 2.5), os argumentos são 4 e 2,5, independentemente de como os parâmetros foram nomeados.

C

Cadeia de escopos
A cadeia de escopos é a sequência do escopo atual e dos escopos que o envolvem, pesquisados para fora para resolver um nome, parando na primeira declaração.
Um cálculo interno lê seu amount local antes de considerar uma variável de mesmo nome em um escopo externo.
Cadeia de métodos
Uma cadeia de métodos usa o valor retornado por um método como receptor do método seguinte, permitindo várias etapas de processamento de vetores em sequência.
Um filter seguido por um map primeiro seleciona entradas e depois transforma apenas os elementos mantidos.
Caso base
Um caso base é o caminho de parada de uma função recursiva, que retorna sem outra chamada a si mesma quando o problema chega a uma forma simples.
Para um fatorial de inteiros não negativos, o teste n <= 1 interrompe as chamadas em 0 ou 1.
Caso recursivo
Um caso recursivo trata o problema chamando a mesma função com uma entrada reduzida e usando o resultado retornado para concluir a chamada atual.
A expressão n * factorial(n - 1) espera pelo fatorial menor antes de multiplicar pelo n desta chamada.
Chamada de função
Uma chamada de função invoca uma função usando parênteses após um valor de função, com eventuais argumentos dentro desses parênteses.
Escrever sayHi() executa seu corpo, enquanto uma linha contendo apenas sayHi lê o valor da função.
Cláusula de guarda
Uma cláusula de guarda verifica uma condição especial e encerra a chamada antecipadamente, mantendo esse caminho excepcional separado do trabalho principal da função.
O teste if (b === 0) { return null; } protege a divisão colocada depois dele em safeDivide.
Comparador
Um comparador é uma função de retorno de ordenação cujo valor de retorno negativo, positivo ou zero determina a ordem relativa de duas entradas comparadas.
O comparador (a, b) => a - b ordena números em ordem crescente enquanto sort reorganiza o vetor de entrada.
Composição
A composição combina funções passando a saída de uma função para a entrada de outra, com a chamada interna executada antes da externa.
Com f(g(x)), mudar a ordem para g(f(x)) pode alterar o resultado mesmo quando ambas as funções aceitam números.
Corpo conciso
Um corpo conciso é um corpo de função de seta formado por uma expressão cujo valor se torna o resultado da chamada sem uma instrução return explícita.
O corpo de expressão em (a, b) => a + b retorna diretamente a soma dos dois argumentos fornecidos.
Corpo da função
O corpo da função contém as instruções executadas durante uma chamada; uma função comum envolve essas instruções em chaves.
Se o corpo de printHeading contém três instruções de impressão, todas as três são executadas novamente a cada chamada dessa função.
Corpo em bloco
Um corpo em bloco contém instruções dentro de chaves e exige um return explícito para que uma função de seta retorne um valor calculado.
A função de seta (n) => { n * 2; } calcula um produto, mas retorna undefined porque não tem uma instrução de retorno.

D

Declaração de função
Uma declaração de função define uma função nomeada com a palavra-chave function e a disponibiliza desde o início de seu escopo.
A chamada greet("Li") pode aparecer acima da declaração escrita de greet no mesmo escopo.
Desestruturação de vetores
A desestruturação de vetores atribui elementos de um vetor a nomes individuais, permitindo que um vetor retornado forneça vários resultados nomeados.
A declaração const [low, high] = minMax(values); extrai os dois elementos do vetor retornado.

E

Efeito colateral
Um efeito colateral é uma alteração fora do cálculo local de uma função, como imprimir, alterar uma variável externa ou modificar um vetor de entrada.
Uma função de retorno que adiciona um elemento a uma lista compartilhada tem um efeito colateral mesmo que também retorne um valor útil.
Elevação
A elevação descreve o registro de declarações antes da execução de seu escopo, com regras diferentes de acesso antecipado para funções, var, let e const.
Ler um var que passou por elevação antes de sua atribuição fornece undefined; uma chamada antecipada a uma declaração de função pode ser executada.
Escopo de bloco
O escopo de bloco restringe uma declaração let ou const ao bloco que a contém e ao código aninhado, mantendo essa declaração indisponível ao código externo.
Um let message declarado em um corpo if não pode ser lido por uma instrução após o fim desse bloco.
Escopo de função
O escopo de função torna um parâmetro ou uma declaração var local à função que o contém, mesmo quando var é escrito dentro de um bloco interno.
Um var result atribuído em um bloco if pode ser retornado mais tarde pelo corpo da função que o contém.
Escopo global
O escopo global contém declarações de nível superior de um script comum, disponibilizando esses nomes para funções cujas cadeias de escopos os alcançam.
Um count de nível superior de um script pode se tornar estado compartilhado quando várias funções o leem ou atualizam.
Escopo léxico
O escopo léxico determina as declarações externas acessíveis pelo aninhamento do código escrito, em vez do local de uma chamada posterior.
Uma função de leitura de nível superior ainda lê sua variável externa quando chamada dentro de uma função com uma variável local de mesmo nome.
Estado compartilhado
Estado compartilhado é um conjunto de dados preservados que mais de uma função pode acessar e atualizar, como uma vinculação capturada por funções da mesma chamada.
Uma operação de depósito e uma função de leitura de saldo retornadas juntas podem acessar o mesmo balance privado.
Estado privado
Estado privado são dados dentro do escopo local de um fechamento que o código externo só pode acessar ou alterar por meio das operações que os expõem.
Um limitador expõe uma operação de permitir ou rejeitar enquanto mantém sua contagem interna used inacessível diretamente.
Expressão de função
Uma expressão de função cria uma função como valor dentro de uma expressão, como o lado direito de uma atribuição a uma variável.
Em const square = function (n) { return n * n; };, a expressão fornece o valor armazenado em square.
Expressão de função imediatamente invocada (IIFE)
Uma expressão de função imediatamente invocada, ou IIFE, cria uma função e a chama de imediato, frequentemente para dar um escopo privado a código antigo.
Os parênteses finais em (function () { var hidden = 1; })(); invocam a função recém-criada.
Expressão de função nomeada
Uma expressão de função nomeada cria uma função com um nome interno disponível dentro de seu próprio corpo, inclusive para chamadas recursivas.
Em const factorial = function fact(n) { /* body */ };, a variável externa é factorial, e o nome interno é fact.

F

Fábrica de funções
Uma fábrica de funções cria e retorna funções configuradas, usando o acesso por fechamento para manter os argumentos ou o estado local de sua invocação.
Chamar makeMultiplier(3) retorna uma função que mantém 3 na memória enquanto aceita um número posterior para multiplicar.
Fechamento
Um fechamento combina uma função com acesso preservado a seu escopo de criação, permitindo que variáveis capturadas permaneçam utilizáveis após um retorno externo.
Uma função de contador pode continuar incrementando seu count privado depois que a fábrica que a criou terminou.
Função
Uma função é um conjunto reutilizável de instruções que executa uma tarefa quando chamado, podendo aceitar entradas e retornar um resultado.
Um script chama printHeading("Report") e printHeading("Totals") para reutilizar uma rotina de cabeçalho.
Função anônima
Uma função anônima é uma expressão de função sem um nome explícito de função, frequentemente armazenada em uma variável ou passada como argumento.
A expressão function (n) { return n * n; } não tem um nome interno de função em sua sintaxe escrita.
Função de ordem superior
Uma função de ordem superior aceita uma função como argumento, retorna uma função como resultado ou combina as duas formas de tratar valores de função.
Métodos de vetor aceitam funções de retorno, enquanto uma fábrica de multiplicadores retorna uma função de cálculo configurada.
Função de retorno
Uma função de retorno é passada como argumento para uma função receptora invocar, sendo esta responsável por controlar suas entradas e o uso de seu retorno.
Uma função auxiliar countIf chama sua função de retorno de teste para cada item e conta aqueles cujos resultados são avaliados como verdadeiros.
Função de retorno adiada
Uma função de retorno adiada é agendada para execução posterior, enquanto o código após a chamada de agendamento pode continuar sem esperar que ela seja executada.
Passar sayHi para setTimeout permite que as instruções seguintes sejam executadas antes de a saudação agendada aparecer.
Função de retorno de transformação
Uma função de retorno de transformação retorna um valor substituto para um item de entrada, permitindo que uma função de mapeamento colete as saídas em um novo vetor.
A função de retorno (n) => n * n transforma os elementos de [1, 2, 3] em quadrados por meio de uma operação de mapeamento.
Função de retorno síncrona
Uma função de retorno síncrona é executada durante a execução da função receptora, concluindo seu trabalho antes que esta retorne a quem a chamou.
Uma função de retorno de map processa os elementos do vetor antes que a chamada de map concluída forneça seu vetor de resultado.
Função de seta
Uma função de seta é uma expressão de função escrita com uma seta entre seus parâmetros e seu corpo, sem suas próprias vinculações de this ou arguments.
A função de seta (n) => n * 2 fornece uma função de retorno de transformação curta a um método de vetor como map.
Função definida no ponto de uso
Uma função definida no ponto de uso é uma expressão de função escrita diretamente onde seu valor é necessário, como uma função de seta dentro da lista de argumentos de uma chamada.
A função de seta em repeat(3, (i) => console.log(i)) fornece a ação sem uma declaração nomeada separada.
Função envoltória
Uma função envoltória é uma função retornada que acrescenta comportamento ao redor de uma chamada de função existente, frequentemente repassando suas entradas e preservando seu resultado.
Uma função envoltória de registro imprime os argumentos fornecidos, chama a função original e depois retorna seu resultado.
Função envoltória de execução única
Uma função envoltória de execução única mantém um indicador de conclusão e um primeiro resultado para que chamadas posteriores possam reutilizar esse resultado sem repetir uma operação concluída.
Um indicador separado permite que uma função envoltória de execução única registre que sua primeira chamada terminou mesmo quando o resultado foi 0.
Função pura
Uma função pura calcula sua saída apenas a partir de seus argumentos e não faz alterações fora da chamada, incluindo saída no console.
Uma função que apenas retorna n * 2 é pura; imprimir o produto introduziria um efeito colateral.

L

Literal de objeto
Um literal de objeto cria um objeto usando chaves e propriedades nomeadas; para retorná-lo de um corpo conciso de função de seta, ele é envolvido em parênteses.
A função de seta (n) => ({ value: n }) retorna um objeto em vez de tratar suas chaves como um bloco de instruções.

M

Modo estrito
O modo estrito é um modo de execução do JavaScript que rejeita atribuições a nomes não declarados, ajudando a evitar variáveis globais acidentais.
Começar um script comum com "use strict"; faz uma atribuição count = 5; sem declaração gerar um ReferenceError.
Mutação
Uma mutação altera o conteúdo de um valor existente, como um vetor, tornando a alteração visível por outras referências a esse vetor.
Uma função que chama arr.push(3) altera o mesmo vetor que quem a chamou forneceu como argumento.

N

Notação camelCase
A notação camelCase é um estilo de nomeação com a primeira palavra em minúsculas e as palavras seguintes iniciadas por maiúsculas, comumente usado para nomes de funções JavaScript.
O nome calculateTotal descreve uma ação e separa suas duas palavras sem espaços ou sublinhados.

O

Objeto arguments
O objeto arguments é uma coleção semelhante a um vetor que contém as entradas passadas a uma função comum, diferente de um vetor verdadeiro de parâmetro rest.
Código antigo pode ler arguments[0], mas não pode chamar arguments.map como um método comum de vetor.

P

Parâmetro
Um parâmetro é um nome local na definição de uma função que recebe um valor de um argumento quando a função é chamada.
Os nomes width e height são parâmetros em function area(width, height) { return width * height; }.
Parâmetro padrão
Um parâmetro padrão usa uma expressão especificada quando seu argumento é undefined, inclusive quando quem chama a função omite esse argumento.
O parâmetro level = 50 mantém um 0 explícito, mas fornece 50 quando o argumento está ausente.
Parâmetro rest
Um parâmetro rest coleta os argumentos restantes da chamada em um vetor verdadeiro e aparece como último parâmetro, precedido por três pontos.
Em function log(label, ...values) { /* body */ }, o primeiro argumento fica separado do vetor rest.
Pilha de chamadas
A pilha de chamadas registra chamadas de função não concluídas, colocando cada nova invocação no topo e removendo seu quadro quando essa chamada retorna.
Enquanto sumOfSquares espera por square(3), a chamada de square tem um quadro acima do quadro de quem a chamou e está em espera.
Predicado
Um predicado é uma função de teste cujo resultado decide se uma entrada satisfaz uma condição, usada por métodos como filter ou find.
O predicado (n) => n > 4 seleciona quais números um filtro mantém sem alterar seus valores por si mesmo.

Q

Quadro de pilha
Um quadro de pilha contém o estado de execução de uma chamada de função ativa, incluindo seus parâmetros, variáveis locais e ponto de continuação.
Duas chamadas recursivas ativas podem manter valores diferentes de n porque têm quadros separados.

R

Rastreamento de pilha
Um rastreamento de pilha lista as chamadas ativas quando ocorreu um erro, começando pela mais recente e seguindo pelas chamadas que a originaram.
Entradas repetidas para uma função recursiva podem ajudar a localizar uma condição de parada que a entrada nunca alcança.
Reatribuição
Uma reatribuição altera o valor armazenado em uma variável ou parâmetro existente, sem alterar outra variável que continha o valor antigo.
Dentro de uma função, arr = [] redireciona o parâmetro sem substituir a referência ao vetor de quem chamou a função.
Recursão
A recursão ocorre quando uma função chama a si mesma para resolver instâncias menores de uma tarefa, com um caso de parada que não precisa de outra chamada a si mesma.
Uma função de fatorial multiplica sua entrada pelo resultado da mesma função para uma entrada uma unidade menor.
Referência a uma função
Uma referência a uma função é um valor que identifica uma função, permitindo que outra variável ou função receptora chame essa mesma função mais tarde.
Após const alias = square;, chamar alias(4) invoca a função também acessada por square.
Retorno antecipado
Um retorno antecipado encerra uma chamada antes que suas instruções posteriores sejam executadas, frequentemente tratando uma entrada especial antes do trabalho principal da função.
Uma função auxiliar de divisão pode retornar null para um divisor zero antes que a execução chegue à instrução de divisão.

S

Sintaxe de espalhamento
A sintaxe de espalhamento expande os elementos de um vetor em argumentos separados de uma chamada, usando três pontos antes da expressão do vetor na lista de argumentos.
Chamar Math.max(...[3, 7, 2]) passa três números em vez de passar um vetor para Math.max.
Sombreamento
O sombreamento ocorre quando uma declaração interna oculta uma declaração externa de mesmo nome dentro do escopo interno, dando ao nome uma vinculação diferente.
Um parâmetro chamado count oculta um count externo dentro dessa função sem alterar a vinculação externa.

V

Valor avaliado como falso
Um valor avaliado como falso se comporta como falso em um teste de condição, razão pela qual um valor padrão definido pelo antigo uso de OU lógico pode substituir entradas válidas como zero.
A expressão level || 50 substitui 0, enquanto um parâmetro padrão preserva esse valor fornecido.
Valor de retorno
Um valor de retorno é o único valor produzido por uma chamada de função e fornecido a quem a chamou para armazenamento ou uso em outra expressão.
Se double(5) retorna 10, a expressão double(5) + 1 pode usar esse valor imediatamente para produzir 11.
Variável capturada
Uma variável capturada é uma vinculação acessada por um fechamento, permitindo que a função leia seu valor atual em vez de uma cópia fixa do momento da criação.
Alterar um greeting externo de “Hi” para “Hello” muda o valor que uma chamada posterior a uma função que lê greeting retorna.
Variável local
Uma variável local pertence a um escopo limitado de função ou bloco, permitindo que seus dados de trabalho permaneçam separados de dados externos com nomes semelhantes.
Duas funções independentes podem usar, cada uma, um total local sem que suas adições afetem umas às outras.
Vinculação
Uma vinculação associa um nome a um valor armazenado em um escopo específico, permitindo que variáveis de mesmo nome em escopos diferentes permaneçam distintas.
Uma atribuição atualiza a vinculação acessível mais próxima; uma declaração interna cria uma vinculação local separada.
Vinculação por iteração
Uma vinculação por iteração é a vinculação separada de variável de laço criada para uma iteração por let no cabeçalho de um laço for, que fechamentos podem manter.
Funções de seta armazenadas de iterações diferentes de let i podem retornar valores diferentes após o término do laço.

Z

Zona morta temporal
A zona morta temporal é o intervalo antes da inicialização de uma vinculação let ou const, quando acessar essa vinculação gera um ReferenceError.
Uma leitura antecipada encontra uma variável local que sombreia outra mesmo quando ainda não está inicializada, em vez de usar um valor externo.

Sobre esta aula

Por StudeliRelatar um erro

Crie seus próprios Materiais de Estudo

Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.

Começar