W3docs

JavaScript eval()

Aprenda como a função eval() do JavaScript executa uma string como código: sintaxe, valor de retorno, chamadas diretas e indiretas, riscos de segurança e alternativas.

JavaScript pode transformar uma string em código em execução durante o tempo de execução. A função embutida eval() faz exatamente isso: recebe uma string, trata-a como código-fonte JavaScript e a executa. Esta página explica como eval() funciona, onde ela retorna um valor, por que quase sempre é a ferramenta errada e o que usar em vez dela.

Esta página aborda:

  • A sintaxe de eval() e o que ela retorna.
  • Casos de uso reais (e por que a maioria deles tem alternativas melhores hoje).
  • Os problemas de segurança e desempenho que tornam eval() perigosa.
  • Substitutos mais seguros: o construtor Function e JSON.parse().
  • Boas práticas para os casos raros em que você realmente precisar dela.

Entendendo a Função eval()

eval() avalia ou executa uma string de código JavaScript. Se a string for uma expressão, eval() a avalia e retorna o resultado. Se a string for uma ou mais declarações, eval() as executa e retorna o valor da última declaração de expressão (ou undefined).

Sintaxe

eval(string)

Parâmetros:

  • string — uma string de código-fonte JavaScript a ser avaliada.

Valor de retorno: o resultado da última expressão avaliada, ou undefined se a string não contiver expressões.

Se string não for uma string (por exemplo, um número), eval() retorna o argumento sem alterações.

Exemplo de Uso

Neste exemplo, avaliamos uma expressão aritmética simples e exibimos o resultado:

javascript— editable

Casos de Uso Práticos para eval()

Embora a função eval() possa ser extremamente poderosa, seu uso é frequentemente desencorajado devido a preocupações com segurança e desempenho. No entanto, há cenários em que eval() pode ser útil.

Execução Dinâmica de Código

Em situações onde o código precisa ser gerado e executado dinamicamente, eval() pode ser uma solução prática. Por exemplo, criar uma calculadora que avalia a entrada do usuário como uma expressão matemática:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Dynamic Calculator</title>
</head>
<body>
    <p>Add any arithmetic expression like 12 + 5 and hit 'Calculate' button!</p>
    <div>
        <input type="text" id="expression" placeholder="Enter expression" /> <!-- User input field -->
        <button onclick="evaluateExpression()">Calculate</button> <!-- Button to trigger calculation -->
    </div>
    <div id="calcResult"></div> <!-- Element to display result -->
    <script>
        function evaluateExpression() {
            const expression = document.getElementById('expression').value; // Get user input
            try {
                const result = eval(expression); // Evaluate the expression
                document.getElementById('calcResult').textContent = `Result: ${result}`; // Display the result
            } catch (e) {
                document.getElementById('calcResult').textContent = 'Invalid expression'; // Handle invalid input
            }
        }
    </script>
</body>
</html>

Analisando JSON com eval()

Antes da introdução de JSON.parse(), eval() era usada para analisar strings JSON. No entanto, agora é recomendado usar JSON.parse() por questões de segurança.

javascript— editable

Ao usar eval() para analisar strings JSON, é fundamental garantir que a string JSON seja interpretada como uma expressão de object e não como uma declaração de bloco. Para isso, a string JSON é envolta em parênteses antes de ser passada para eval(). Isso garante que o JavaScript trate a string como uma expressão de object, evitando erros de sintaxe que poderiam ocorrer se a string fosse interpretada como uma declaração de bloco.

Informação

Sempre prefira JSON.parse() em vez de eval() para analisar JSON. JSON.parse() aceita apenas dados, portanto nunca pode executar um script injetado.

eval Direto vs. Indireto e Escopo

Como eval() enxerga variáveis depende de como você a chama.

Uma chamada diretaeval(code) escrita literalmente — executa o código no escopo atual. Ela pode ler e até criar variáveis no local onde é chamada:

javascript— editable

Uma chamada indireta — chamar eval por meio de qualquer referência que não seja o nome literal, como (0, eval)(code) ou armazenando-a em uma variável — executa o código no escopo global. Ela não consegue ver variáveis locais:

javascript— editable

No modo estrito, até mesmo um eval() direto obtém seu próprio escopo: as variáveis que ele declara não vazam para a função ao redor. Esse é mais um motivo pelo qual o código moderno raramente precisa de eval().

Preocupações com Segurança e Desempenho

O uso de eval() pode apresentar riscos de segurança significativos e problemas de desempenho. Veja por quê:

Riscos de Segurança

eval() pode executar qualquer código JavaScript, tornando-a vulnerável a ataques de injeção. Um invasor poderia potencialmente injetar código malicioso, levando a graves violações de segurança.

Exemplo de Risco de Segurança:

Imagine que você tem uma aplicação web que recebe entrada do usuário e a avalia usando eval(). Sem a validação adequada, isso pode ser explorado por um invasor para executar código malicioso.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>eval() Security Risk Example</title>
</head>
<body>
    <div>
     <p>Hit 'Run Code' button!</p>
        <input type="text" id="userInput" placeholder="Enter code" value="alert('Hacked!')" /> <!-- User input field -->
        <button onclick="evaluateUserInput()">Run Code</button> <!-- Button to run code -->
    </div>
    <div id="userInputResult"></div> <!-- Element to display result -->
    <script>
        function evaluateUserInput() {
            const input = document.getElementById('userInput').value; // Get user input
            try {
                const result = eval(input); // Evaluate the user input
                document.getElementById('userInputResult').textContent = `Result: ${result}`; // Display the result
            } catch (e) {
                document.getElementById('userInputResult').textContent = 'Error in evaluation'; // Handle evaluation error
            }
        }
    </script>
</body>
</html>

Neste exemplo, se um usuário inserir algo como alert('Hacked!'), a função eval() irá executá-lo, causando uma violação de segurança ao exibir uma caixa de alerta. Um invasor poderia injetar código mais prejudicial, potencialmente comprometendo todo o sistema.

Problemas de Desempenho

eval() executa código no mesmo escopo de onde é chamada, impedindo otimizações do motor JavaScript. Isso pode resultar em desempenho mais lento em comparação com outras abordagens.

Exemplo de Problema de Desempenho:

Considere um cenário onde precisamos realizar uma série de cálculos várias vezes. Usar eval() para essa tarefa pode impactar significativamente o desempenho.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Performance Issues with eval()</title>
</head>
<body>
    <div id="evalResult"></div>
    <div id="functionResult"></div>
    <script>
        // Using eval()
        const evalStartTime = performance.now();
        for (let i = 0; i < 100000; i++) {
            eval("3 * 4 + 5");
        }
        const evalEndTime = performance.now();
        const evalDuration = evalEndTime - evalStartTime;
        document.getElementById('evalResult').textContent = `Time taken with eval(): ${evalDuration} ms`;

        // Using Function constructor
        const func = new Function('return 3 * 4 + 5');
        const funcStartTime = performance.now();
        for (let i = 0; i < 100000; i++) {
            func();
        }
        const funcEndTime = performance.now();
        const funcDuration = funcEndTime - funcStartTime;
        document.getElementById('functionResult').textContent = `Time taken with Function constructor: ${funcDuration} ms`;
    </script>
</body>
</html>

Neste exemplo, comparamos o desempenho de eval() com o construtor Function. Executamos uma operação aritmética simples (3 * 4 + 5) 100.000 vezes usando ambos os métodos e medimos o tempo gasto em cada um.

  • Usando eval(): O código dentro de eval() é avaliado repetidamente, o que é mais lento porque impede certas otimizações.
  • Usando o Construtor Function: O construtor Function cria uma função que realiza a mesma operação, mas é mais rápido porque permite que os motores JavaScript otimizem a execução repetida.

Os resultados exibidos na página mostram o tempo gasto por cada método, demonstrando que eval() é mais lenta devido aos seus problemas de desempenho.

Aviso

Evite eval() a menos que seja absolutamente necessário. Recorra primeiro a alternativas mais seguras: o construtor Function para funções dinâmicas ou JSON.parse() para dados.

Alternativas para eval()

Para uma execução de código mais segura e eficiente, considere as seguintes alternativas:

Usando o Construtor Function

O construtor Function cria um novo objeto de função, semelhante a eval(), mas com melhor segurança e desempenho.

javascript— editable

Usando JSON.parse()

Para analisar strings JSON, JSON.parse() é o método preferido.

javascript— editable

Boas Práticas para Usar eval()

Se você precisar usar eval(), siga estas boas práticas para mitigar os riscos:

1. Valide a Entrada

Certifique-se de que a entrada para eval() seja estritamente validada para evitar injeção de código. Isso significa permitir apenas caracteres e expressões seguros.

Exemplo:

javascript— editable

Neste exemplo, usamos uma expressão regular para validar a entrada do usuário. Apenas caracteres numéricos e operadores aritméticos básicos são permitidos. Se a entrada corresponder ao padrão, ela é avaliada com eval(). Caso contrário, é rejeitada como inválida.

2. Use Try-Catch

Envolva eval() em um bloco try-catch para tratar possíveis erros de forma adequada. Isso evita que toda a aplicação quebre se eval() encontrar um erro.

Exemplo:

javascript— editable

Aqui, tratamos erros de sintaxe na entrada do usuário usando um bloco try-catch. Se eval() lançar um erro, ele é capturado e uma mensagem de erro é registrada em vez de a aplicação quebrar.

3. Restrinja o Escopo

Minimize o escopo das variáveis acessíveis a eval() para limitar o dano potencial de código malicioso. Use uma expressão de função imediatamente invocada (IIFE) para criar um escopo local.

Exemplo:

javascript— editable

Neste exemplo, definimos uma função restrictedEval dentro de uma IIFE para criar um escopo local. Essa função avalia a entrada usando eval(), mas com variáveis locais a e b. As variáveis globais a e b não são acessíveis, demonstrando a restrição de escopo.

Seguindo essas boas práticas, você pode reduzir os riscos associados ao uso de eval() enquanto ainda aproveita suas capacidades de execução dinâmica de código quando necessário.

Conclusão

A função eval() em JavaScript oferece uma ferramenta poderosa para execução dinâmica de código, mas traz riscos significativos e desvantagens de desempenho. Na prática, quase qualquer tarefa que pareça precisar de eval() tem uma resposta mais segura: use JSON.parse() para dados, o construtor Function para funções dinâmicas e consultas a object/array em vez de construir nomes de variáveis a partir de strings. Se você precisar usar eval(), valide a entrada, envolva-a em try...catch e mantenha seu escopo o menor possível.

Tópicos Relacionados

Prática

Prática
O que a função eval() em JavaScript faz?
O que a função eval() em JavaScript faz?
Was this page helpful?