Alternatives to JavaScript eval()

Alternatives to JavaScript eval()

D
dongAuthor
5 min read

Learn why JavaScript’s eval() is dangerous and how to safely replace it with new Function() using practical examples. Tips to enhance both security and performance!

When working with JavaScript, you may encounter situations where you need to execute code from a string. The first thing that often comes to mind is the eval() function. However, eval() is notorious for its security vulnerabilities and performance issues.

In this article, we’ll explore the dangers of eval() and how you can use the safer alternative new Function() with real-world examples.

What is eval()?

According to the MDN documentation, eval() is a function that executes JavaScript code represented as a string. Let’s look at a simple example to understand how it works:

let a = 3;
let b = 5;
eval('a += ' + b + ' + 2');
console.log(a); // 10

In the code above, eval() executes the string 'a += 5 + 2' as actual JavaScript code. It may seem convenient at first glance, but there are serious issues hidden behind that simplicity.

Security risks of eval()

eval() runs code with the privileges of the caller. What does that mean? If you execute user input with eval(), malicious code can run directly.

var userContent = getUserInput(); // Value from user input
eval(userContent); // Dangerous!

What if a hacker enters something like "window.location = 'http://malicious-site.com'"? The user could be redirected to a malicious site, or worse, sensitive data could be stolen.

eval() can also access the scope in which it’s called. This means it can read and modify local variables:

function MyFunc() {
  let secretToken = "abc123";
  eval('console.log(secretToken); secretToken = "hacked";');
  console.log(secretToken); // "hacked"
}

Performance issues with eval()

Because eval() invokes the JavaScript interpreter directly, it’s slower than other alternatives. Modern JavaScript engines optimize code execution, but eval() prevents those optimizations because the engine can’t predict what code will run.

Using new Function() for safer execution

new Function() is similar to eval() in that it creates a function from a string, but it’s much safer. Let’s see how it works:

const add = new Function('a', 'b', 'return a + b');
console.log(add(2, 3)); // 5

The syntax is as follows:

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

The important point is that functions created with new Function() always execute in the global scope. They cannot access local variables:

function MyFunc() {
  let b = 123;
  new Function('console.log(b);')(); // ReferenceError: b is not defined
}

This restriction actually improves security by preventing malicious code from accessing sensitive variables within the function.

Comparing eval() and new Function()

Here’s a summary of the key differences between the two methods.

Execution context and scope

eval() evaluates code in the current execution context:

function testEval() {
  let x = 10;
  eval('console.log(x); x = 20;');
  console.log(x); // 20 – variable modified
}
testEval();

In contrast, new Function() runs in the global context only:

function testFunction() {
  let x = 10;
  const func = new Function('console.log(typeof x);'); // "undefined"
  func();
  console.log(x); // 10 – variable remains protected
}
testFunction();

Security

The restricted scope of new Function() is a major security advantage. Since it can’t access local variables, even if malicious code runs, the damage is limited.

Learning through practical examples

How can you actually replace eval() with new Function()?

Simple expression evaluation

// Using eval() – not recommended
const result1 = eval('2 + 3 * 4');

// Using new Function() – recommended
const calculate = new Function('return 2 + 3 * 4');
const result2 = calculate();

Creating dynamic functions

// Creating a function from user-provided body
const functionBody = 'return x * 2';
const double = new Function('x', functionBody);
console.log(double(5)); // 10

Passing external variables safely

Global variables are accessible from new Function(), but the safer approach is to pass them explicitly as parameters:

const multiplier = 3;

// Pass as parameter explicitly
const multiply = new Function('x', 'multiplier', 'return x * multiplier');
console.log(multiply(5, multiplier)); // 15

Alternative to JSON parsing

You can even use it to parse JavaScript object literals that aren’t strict JSON:

function looseJsonParse(obj) {
  return Function('"use strict";return (' + obj + ")")();
}

const result = looseJsonParse("{a:(4-1), b:function(){}, c:new Date()}");
console.log(result.a); // 3

When should you use new Function()?

Here are some scenarios where new Function() is particularly useful:

Dynamic code generation

It’s helpful when you need to generate functions based on configuration files or user input—for example, implementing custom filters or sorting logic.

Sandbox environments

Since it runs in the global scope only, it’s a good fit for plugin systems or executing user scripts in a controlled environment.

Performance-critical code

If the code will be executed repeatedly, compiling it once with new Function() and reusing it is more efficient than calling eval() every time.

Cautions and limitations

new Function() isn’t a perfect solution. It still generates code from strings, so untrusted input must be thoroughly validated.

In some edge cases, neither eval() nor new Function() is appropriate. When possible, consider safer alternatives like the following:

Accessing object properties:

// Using eval() (bad)
const propName = 'username';
const value = eval('user.' + propName);

// Using bracket notation (good)
const value = user[propName];

Registering event handlers:

// Inline string (bad)
element.setAttribute("onclick", "handleClick()");

// Event listener (good)
element.addEventListener("click", handleClick);

Using timer functions:

// Code as string (bad)
setTimeout("console.log('Hello')", 1000);

// Passing a function (good)
setTimeout(() => console.log('Hello'), 1000);

Toward safer code

While eval() might seem convenient, it can cause serious security and performance issues. new Function() is a better alternative that significantly reduces those risks by restricting access to the global scope.

Of course, the best approach is to avoid dynamic code execution altogether. But when it’s unavoidable, choose new Function() and ensure all inputs are properly validated.

Security is non-negotiable. Remember that a single line of code can determine the safety of your entire application. Stay safe out there!

Alternatives to JavaScript eval() | devdong