new Function()

Compiles a function from strings at runtime, always in global scope rather than a closure.

Signature
new Function(functionBody)
new Function(arg1, functionBody)
new Function(arg1, arg2, functionBody)
new Function(arg1, arg2, /* …, */ argN, functionBody)

Function(functionBody)
Function(arg1, functionBody)
Function(arg1, arg2, functionBody)
Function(arg1, arg2, /* …, */ argN, functionBody)
  • Added in JavaScript ECMAScript 1 (1997)

Parameters

ParameterTypeDescription
$arg1, …, argNoptionalstring | TrustedScriptNames to be used by the function as formal argument names. Each must be a valid JavaScript parameter — a plain identifier, a rest parameter, or a destructured parameter, optionally with a default. Several parameters may be given in one string separated by commas, and whitespace and comments are accepted.
$functionBodystring | TrustedScriptA string containing the JavaScript statements comprising the function definition.

Return value

FunctionA new Function object; calling Function() with or without new produces the same result.

Errors

Throws a SyntaxError if the parameter strings cannot be parsed as a valid parameter list or the body cannot be parsed as valid statements, and a TypeError if a string is passed while Trusted Types are enforced by CSP with no default policy.

Changelog

  • PHP ECMAScript 2015Parameter strings may use rest, destructuring and default-value syntax, not just plain identifiers.
  • PHP Trusted TypesUnder a CSP that enforces Trusted Types with no default policy, passing plain strings throws a TypeError; TrustedScript values must be used instead.

The Function() constructor turns strings into a live function: the last argument is the body, everything before it names the parameters. It works with or without new.

The one thing that distinguishes it from eval()

The created function is always compiled in global scope. It cannot see any local variable at the point where it was constructed, and its body is non-strict unless it opens with "use strict" — even inside a module or a strict function. That isolation is the only real advantage over eval(), which does capture the surrounding scope.

When to reach for it

Almost never in application code. Legitimate uses are narrow: template compilers and hot-path code generators that build a specialised function once and call it a million times, feature-detecting a syntax an older engine may not parse, and sandboxing a snippet from local scope on purpose.

What trips people up

It is slow — the engine parses and compiles on every construction, so building one inside a loop is a real cost. It is blocked by any Content Security Policy without unsafe-eval, so it will work in development and fail in production. Bundlers cannot see inside the string, so nothing it references gets kept. And if any part of the string comes from user input, this is code injection.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Compile a template into a specialised render function once, then call it repeatedly
  • Feature-detect syntax support without a parse error breaking the whole script
  • Evaluate a mathematical expression string in an isolated global scope
  • Generate an optimised property accessor from a schema at startup

Frequently asked questions

What is the difference between new Function() and eval()?

new Function() compiles its body in global scope, so it cannot read local variables where it was created, while direct eval() runs in the calling scope and can. Function() is therefore more isolated and easier for engines to optimise, though both are blocked by a CSP without unsafe-eval.

Why does new Function() throw an EvalError or fail in production?

Almost always a Content Security Policy without 'unsafe-eval', which blocks runtime compilation; under Trusted Types enforcement passing plain strings throws a TypeError instead. Precompile the code at build time rather than generating it in the browser.

Is it safe to build a function from user input?

No. Any string you concatenate into the body is executed with your application's privileges, which is arbitrary code execution. Parse and interpret untrusted input with your own evaluator, and JSON-escape any value that must appear in generated source.

More examples

No closure: global scope only

The constructed function throws a ReferenceError for outer because it was compiled in global scope, but reads shared fine since that lives on globalThis. Direct eval() in the same place sees outer — that difference is the whole reason to prefer Function() when you want isolation.

Example · javascript
const outer = "local value";
globalThis.shared = "global value";

const peek = new Function(`
  try { return outer; }
  catch (e) { return 'cannot see outer: ' + e.constructor.name; }
`);
console.log(peek());
console.log(new Function("return shared;")());

// eval(), by contrast, does see the local binding
console.log(eval("outer"));

Compiling once and reusing

The path is parsed once and turned into a straight-line accessor, so repeated lookups skip the string splitting entirely. Note JSON.stringify around each key: without that escaping, a key containing a quote would inject arbitrary code into the generated body.

Example · javascript
function compilePath(path) {
  const steps = path.split(".").map((k) => `?.[${JSON.stringify(k)}]`).join("");
  return new Function("obj", `return obj${steps};`);
}

const getCity = compilePath("user.address.city");
console.log(getCity.toString());
console.log(getCity({ user: { address: { city: "Lisbon" } } }));
console.log(getCity({ user: {} }));

Discussion

  • Be the first to comment on this lesson.