Very similar to this Python question but for JavaScript.
I'm using a library that relies on nodejs-depd
which uses new Function()
to dynamically wrap functions in deprecation messages:
function wrapfunction(fn, message) {
if (typeof fn !== "function") {
throw new TypeError("argument fn must be a function");
}
var args = createArgumentsString(fn.length);
var stack = getStack();
var site = callSiteLocation(stack[1]);
site.name = fn.name;
var deprecatedFn = new Function(
"fn",
"log",
"deprecate",
"message",
"site",
'"use strict"\n' +
"return function (" +
args +
") {" +
"log.call(deprecate, message, site)\n" +
"return fn.apply(this, arguments)\n" +
"}"
)(fn, log, this, message, site);
return deprecatedFn;
}
This produces various legitimate concerns about security. But it also produces functions that match the original - if args
are arg0, arg1
, the new function will be
function (arg0, arg1) {
log.call(deprecate, message, site)
return fn.apply(this, arguments)
}
BTW, 'no, this isn't possible' is a fine answer. I just want to find out if this is possible.
It is not possible to dynamically create a function with a specific parameter declaration without eval
/new Function
, but it also not advisable to depend on that - the code (fn.toString()
) is considered an implementation detail.
Yes, it is possible to dynamically create a function with a specific arity, if all you care about in the "signature" is the arity of the function.
The arity (.length
) of a function is a non-writable property, but it's still configurable:
function wrapfunction(fn, message) {
if (typeof fn !== "function") {
throw new TypeError("argument fn must be a function");
}
var stack = getStack();
var site = callSiteLocation(stack[1]);
site.name = fn.name;
var deprecate = this;
var deprecatedFnOld = function() {
log.call(deprecate, message, site);
return fn.apply(this, arguments);
};
Object.defineProperty(deprecatedFnOld, 'length', {value: fn.length});
Object.defineProperty(deprecatedFnOld, 'name', {value: 'deprecated '+fn.name});
return deprecatedFnOld;
}