JavaScript eval()
Learn how JavaScript's eval() function runs a string as code. Covers syntax, return value, security risks, and safer alternatives.
JavaScript can turn a string into running code at runtime. The built-in eval() function does exactly that: it takes a string, treats it as JavaScript source, and runs it. This page explains how eval() works, where it returns a value, why it is almost always the wrong tool, and what to reach for instead.
This page covers:
- The syntax of
eval()and what it returns. - Real use cases (and why most of them have better alternatives today).
- The security and performance problems that make
eval()dangerous. - Safer replacements: the
Functionconstructor andJSON.parse(). - Best practices for the rare cases where you genuinely need it.
Understanding the eval() Function
eval() evaluates or executes a string of JavaScript code. If the string is an expression, eval() evaluates it and returns the result. If the string is one or more statements, eval() runs them and returns the value of the last expression statement (or undefined).
Syntax
eval(string)Parameters:
string— a string of JavaScript source code to evaluate.
Return value: the result of the last expression evaluated, or undefined if the string contains no expressions.
If string is not a string (for example a number), eval() returns the argument unchanged.
Example Usage
In this example we evaluate a simple arithmetic expression and print the result:
Practical Use Cases for eval()
While the eval() function can be immensely powerful, its use is often discouraged due to security and performance concerns. However, there are scenarios where eval() can be useful.
Dynamic Code Execution
In situations where code must be generated and executed dynamically, eval() can be a practical solution. For instance, creating a calculator that evaluates user input as a mathematical expression:
<!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>Parsing JSON with eval()
Before the introduction of JSON.parse(), eval() was used to parse JSON strings. However, it is now recommended to use JSON.parse() due to security concerns.
When using eval() to parse JSON strings, it's crucial to ensure that the JSON string is interpreted as an object expression rather than a block statement. To achieve this, the JSON string is wrapped within parentheses before passing it to eval(). This ensures that JavaScript treats the string as an object expression, preventing syntax errors that could occur if the string were interpreted as a block statement.
Always prefer JSON.parse() over eval() for parsing JSON. JSON.parse() only accepts data, so it can never run an injected script.
Direct vs. Indirect eval and Scope
How eval() sees variables depends on how you call it.
A direct call — eval(code) written literally — runs the code in the current scope. It can read and even create variables where it is called:
An indirect call — calling eval through any reference other than the literal name, such as (0, eval)(code) or storing it in a variable — runs the code in the global scope instead. It cannot see local variables:
In strict mode, even a direct eval() gets its own scope: variables it declares do not leak into the surrounding function. This is one more reason modern code rarely needs eval().
Security and Performance Concerns
Using eval() can pose significant security risks and performance issues. Here’s why:
Security Risks
eval() can execute any JavaScript code, making it vulnerable to injection attacks. An attacker could potentially inject malicious code, leading to severe security breaches.
Example of Security Risk:
Imagine you have a web application that takes user input and evaluates it using eval(). Without proper validation, this can be exploited by an attacker to execute malicious code.
<!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>In this example, if a user enters something like alert('Hacked!'), the eval() function will execute it, causing a security breach by displaying an alert box. An attacker could inject more harmful code, potentially compromising the entire system.
Performance Issues
eval() executes code in the same scope from which it’s called, hindering JavaScript engine optimizations. This can lead to slower performance compared to other approaches.
Example of Performance Issue:
Let's consider a scenario where we need to perform a series of calculations multiple times. Using eval() for this task can significantly impact performance.
<!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>In this example, we compare the performance of eval() with the Function constructor. We execute a simple arithmetic operation (3 * 4 + 5) 100,000 times using both methods and measure the time taken for each.
- Using
eval(): The code insideeval()is evaluated repeatedly, which is slower because it prevents certain optimizations. - Using
FunctionConstructor: TheFunctionconstructor creates a function that performs the same operation, but it's faster because it allows JavaScript engines to optimize the repeated execution.
The results displayed on the webpage show the time taken by each method, demonstrating that eval() is slower due to its performance issues.
Avoid eval() unless absolutely necessary. Reach for safer alternatives first: the Function constructor for dynamic functions, or JSON.parse() for data.
Alternatives to eval()
For safer and more efficient code execution, consider the following alternatives:
Using Function Constructor
The Function constructor creates a new function object, similar to eval(), but with better security and performance.
Using JSON.parse()
For parsing JSON strings, JSON.parse() is the preferred method.
Best Practices for Using eval()
If you must use eval(), adhere to these best practices to mitigate risks:
1. Validate Input
Ensure the input to eval() is strictly validated to prevent code injection. This means allowing only safe characters and expressions.
Example:
In this example, we use a regular expression to validate the user input. Only numeric characters and basic arithmetic operators are allowed. If the input matches the pattern, it is evaluated with eval(). Otherwise, it is rejected as invalid.
2. Use Try-Catch
Wrap eval() in a try-catch block to handle potential errors gracefully. This prevents the entire application from crashing if eval() encounters an error.
Example:
Here, we handle syntax errors in the user input using a try-catch block. If eval() throws an error, it is caught, and an error message is logged instead of crashing the application.
3. Restrict Scope
Minimize the scope of variables accessible to eval() to limit potential damage from malicious code. Use an immediately invoked function expression (IIFE) to create a local scope.
Example:
In this example, we define a function restrictedEval inside an IIFE to create a local scope. This function evaluates the input using eval() but with locally defined variables a and b. The global variables a and b are not accessible, demonstrating scope restriction.
By following these best practices, you can reduce the risks associated with using eval() while still leveraging its dynamic code execution capabilities when necessary.
Conclusion
The eval() function in JavaScript provides a powerful tool for dynamic code execution, but it comes with significant risks and performance drawbacks. In practice almost any task that seems to need eval() has a safer answer: use JSON.parse() for data, the Function constructor for dynamic functions, and object/array lookups instead of building variable names from strings. If you must use eval(), validate input, wrap it in try...catch, and keep its scope as small as possible.
Related Topics
- The "new Function" syntax — the safer way to build a function from a string.
- Working with JSON —
JSON.parse()andJSON.stringify(). - Error handling: try...catch — catching errors thrown by evaluated code.
- Strict mode: "use strict" — how strict mode changes
eval()scope.