new Function()
Compiles a function from strings at runtime, always in global scope rather than a closure.
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
| Parameter | Type | Description |
|---|---|---|
$arg1, …, argNoptional | string | TrustedScript | Names 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. |
$functionBody | string | TrustedScript | A 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
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.
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.
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