New Functions With new
Version: ES2015 (generator), ES2017 (async)
Level: Advanced
Just about any time you create a new function in JavaScript, you’re more than likely going to be using some kind of function declaration or expression to do so. But functions, being objects, also have a constructor. And that constructor can be used to create new functions, just like any other object constructor can be used to create new objects.
The Function
constructor is called using new Function()
(or just Function()
) and takes a variable number of arguments. The last argument is a string representing the code in the body of the function while every other argument before that represents its parameter names.
let logger = new Function('value', 'console.log("[LOG] " + value)');
logger('is wood'); // [LOG] is wood
Functions created with the Function
constructor are similar to function expressions created with the function
keyword. One noticeable difference is that code within the Function
constructor does not have access to any outside scope other than global. While this can be limiting, it can also make it a safer alternative to eval
since it doesn’t expose variables in other scopes.
function runSecretTest () {
let local = 'secret';
function normal () {
console.log('Normal: ' + local);
}
function evaled () {
eval('console.log("Eval: " + local)');
}
let constructed = new Function(
'console.log("Constructor: " + local)'
);
normal(); // Normal: secret
evaled(); // Eval: secret
constructed(); // ReferenceError: local is not defined
}
runSecretTest();
Unique function constructors also exist for generator and async functions (and async generator functions). Unfortunately, these are not exposed globally. To get access to these constructors, you’d need to make a generator or async function first, then access their constructor
properties.
let GeneratorFunction = (function * () {}).constructor;
let count3 = new GeneratorFunction(
'yield 1; yield 2; yield 3;'
);
console.log([...count3()]); // [1, 2, 3]
let AsyncFunction = (async function () {}).constructor;
let delay3 = new AsyncFunction(
'return 3'
);
delay3()
.then(value => console.log(value)); // 3
There is no constructor for arrow functions. If you attempt to access constructor
from an arrow function, it will refer to the standard Function
constructor. The only way to create an arrow function with arrow function-like behavior is using arrow function syntax.
let arrow = () => {};
console.log(arrow.constructor === Function); // true
More info: