W3docs

Sintaxe de Funções JavaScript

Aprenda a sintaxe "new Function" em JavaScript: como criar funções a partir de strings em tempo de execução, regras de escopo, segurança versus eval e quando usá-la.

Na maioria das vezes, você cria uma função com uma declaração, uma expressão ou uma arrow function. Mas o JavaScript tem mais uma forma: o construtor new Function, que cria uma função a partir de strings em tempo de execução. Esta página foca nessa sintaxe — sua forma exata, as regras de escopo que surpreendem a maioria dos desenvolvedores, como ela se compara ao eval e o conjunto restrito de casos em que ela é a ferramenta certa.

A Sintaxe new Function

A sintaxe new Function permite criar uma função cujos parâmetros e corpo são fornecidos como strings. Como o corpo é apenas texto até o motor analisá-lo, você pode montar uma função cujo código não é conhecido quando você escreve o programa — apenas no momento em que ele é executado.

A forma geral é:

let func = new Function([arg1, arg2, ...argN], functionBody);

Cada argumento é uma string. Os primeiros argumentos nomeiam os parâmetros; o último argumento é sempre o corpo da função.

javascript— editable

Você pode passar todos os nomes de parâmetros em uma única string separada por vírgulas, o que é equivalente:

javascript— editable

A palavra-chave new é opcional aqui — Function('a', 'b', 'return a + b') produz o mesmo resultado — mas escrever new Function(...) é a forma convencional e mais clara.

Por Que Existe

A principal diferença entre new Function e uma declaração normal é que o corpo vem de uma string. Essa string pode ser recebida de qualquer lugar: uma resposta do servidor, um template, configurações do usuário ou texto construído em tempo de execução. Portanto, a sintaxe existe exatamente para os casos em que o código que você quer executar ainda não existe quando você escreve o programa.

Escopo: a Grande Armadilha

Este é o detalhe que pega todo mundo de surpresa. Uma função criada com new Function não captura o escopo onde foi criada. Ao contrário de um closure normal, seu ambiente léxico externo é o escopo global, não o local.

function makeAdder() {
  let outer = 100;
  // This function tries to read `outer`...
  return new Function('x', 'return x + outer');
}

const add = makeAdder();
add(5); // ReferenceError: outer is not defined

Uma função regular escrita da mesma forma fecharia sobre outer sem problemas. A versão com new Function não consegue — ela só enxerga seus próprios parâmetros e o escopo global:

javascript— editable

Isso é intencional. Se new Function pudesse acessar variáveis locais, os minificadores (que renomeiam outer para a, secret para b, e assim por diante) quebrariam qualquer código que referenciasse esses nomes como strings. Ao restringir o acesso ao escopo global, a linguagem mantém a minificação segura. A conclusão prática: passe tudo o que uma função dinâmica precisa através de seus argumentos — nunca espere que ela leia variáveis do entorno.

Propriedades de uma Função Dinâmica

Uma função criada dessa forma é um objeto de função normal em todos os outros aspectos, com uma peculiaridade — seu name é sempre "anonymous":

javascript— editable

Esse nome quase vazio é um dos motivos pelos quais funções dinâmicas são mais difíceis de ler em rastreamentos de pilha — veja a nota sobre depuração abaixo.

new Function vs. eval

Tanto new Function quanto eval transformam strings em código executável, mas se comportam de maneira bem diferente:

  • eval(str) executa str no escopo atual, então pode ler e até modificar variáveis locais próximas. Esse acoplamento estreito dificulta a otimização e facilita o uso indevido.
  • new Function é isolado do escopo local (como mostrado acima) e retorna uma função reutilizável em vez de uma avaliação pontual.

Para o raro caso em que você genuinamente precisa executar código de uma string, new Function é a opção mais segura das duas, pois seu raio de impacto se limita ao escopo global e seus parâmetros explícitos.

Aplicações Práticas e Exemplos

Abaixo há um exemplo completo e executável que você pode editar e executar no navegador.

"Experimente Você Mesmo" não está disponível para este exemplo.

Insights Avançados sobre Criação Dinâmica de Funções

A criação dinâmica de funções em JavaScript, facilitada pela sintaxe new Function, é uma técnica poderosa que permite aos desenvolvedores construir funções a partir de strings de código em tempo de execução. Essa capacidade é especialmente útil em cenários onde o código a ser executado não é estático ou conhecido antecipadamente, como em aplicações que exigem um alto grau de flexibilidade ou em situações onde scripts são gerados ou modificados dinamicamente. Nesta seção, vamos nos aprofundar na mecânica, nos benefícios e nas considerações da criação dinâmica de funções, oferecendo uma compreensão mais rica e exemplos práticos para ilustrar seu potencial.

Mecânica da Criação Dinâmica de Funções

A sintaxe new Function cria uma nova instância de função. Os argumentos para o construtor new Function são strings que representam os argumentos da função, seguidos de uma string que representa o corpo da função.

javascript— editable

Isso é funcionalmente equivalente a declarar uma função da maneira tradicional, mas com a diferença fundamental de ser possível montar o código da função dinamicamente, em tempo de execução.

Benefícios da Criação Dinâmica de Funções

  1. Flexibilidade e Personalização: A criação dinâmica de funções permite um alto grau de personalização, pois as funções podem ser geradas com base em entrada do usuário, configurações ou outros dados de tempo de execução.
  2. Scripting e Templating: É especialmente útil na implementação de soluções de scripting personalizadas ou motores de template onde a lógica do template precisa ser avaliada em tempo de execução.
  3. Isolamento e Segurança: Quando usada com cuidado, pode executar código em um ambiente mais controlado, potencialmente isolando o código executado dinamicamente do contexto principal da aplicação.

Considerações e Boas Práticas

Embora a criação dinâmica de funções seja poderosa, ela traz seu próprio conjunto de considerações:

  1. Segurança: A principal preocupação é a segurança. Como o código da função é construído a partir de strings, há risco de execução de código malicioso se a entrada não for devidamente sanitizada. Sempre valide e sanitize a entrada que será usada para gerar código de função.
  2. Desempenho: Funções criadas dinamicamente podem ter desempenho inferior ao das suas contrapartes declaradas estaticamente, pois o motor JavaScript deve analisar a string do corpo da função toda vez que uma nova função é criada. Use esse recurso com critério, especialmente em caminhos críticos de desempenho.
  3. Depuração: Depurar funções geradas dinamicamente pode ser mais desafiador, pois o código não existe até o tempo de execução. Fornecer nomes significativos a funções criadas dinamicamente pode ajudar a mitigar esse problema.
  4. Limitação de Escopo Léxico: Funções criadas com new Function não capturam o escopo local onde são definidas. Elas só têm acesso a variáveis globais e aos seus próprios parâmetros. Isso pode gerar ReferenceErrors se você esperar que elas acessem variáveis externas. (Veja a seção Escopo acima; passe os dados através dos argumentos.)

Exemplo Avançado: Um Motor de Template Simples

Para ilustrar o uso prático da criação dinâmica de funções, considere a implementação de um motor de template simples. Esse motor substituirá espaços reservados em uma string de template por valores de um objeto de dados — e, de forma crucial, os dados são passados como argumento, contornando a limitação de escopo.

javascript— editable

Nota: A sequência \${ escapa a sintaxe de template literal. Isso impede que o espaço reservado ${expr} seja avaliado imediatamente, garantindo que seja passado como uma string literal para o corpo da função gerada.

Este exemplo demonstra não apenas a flexibilidade oferecida pela criação dinâmica de funções, mas também destaca a importância da construção cuidadosa e da sanitização da entrada para evitar riscos de segurança.

Resumo

O construtor new Function cria uma função a partir de strings em tempo de execução:

let func = new Function([arg1, ..., argN], functionBody);

Pontos-chave a lembrar:

  • O último argumento é sempre o corpo da função; os anteriores nomeiam os parâmetros.
  • O escopo externo de uma função criada dinamicamente é global, não o local onde ela foi criada — ela não pode fechar sobre variáveis locais, então passe os dados através dos argumentos.
  • É geralmente mais seguro que eval (que é executado no escopo atual), mas ambos avaliam strings, portanto forneça apenas entradas confiáveis e sanitizadas.
  • Use-o para código genuinamente dinâmico — motores de template, avaliadores de expressões em sandbox, handlers gerados em tempo de execução — e prefira funções ou arrow functions em todos os outros casos.

Para se aprofundar em tópicos relacionados, veja JavaScript Closures, Escopo de Variáveis e Expressões de Função.

Prática

Prática
Quais são as características e boas práticas associadas à sintaxe new function em JavaScript?
Quais são as características e boas práticas associadas à sintaxe new function em JavaScript?
Was this page helpful?