I'm looking for a vanilla JavaScript solution.
Say I've got a function with the following header:
generateEmail(firstName, lastname, provider)
I need to run it like this:
generateEmail("John","Smith","gmail.com");
I would like to be able to call it with argument map instead of positional arguments, i.e.
generateEmail({
"firstName":"John",
"lastname": "Smith",
"provider": "gmail.com"
});
And I'm looking for an already-written solution to do this in JavaScript, since I've got an unlimited number of functions such as generateEmail above to handle. Does such library exist?
I have seen https://github.com/kilianc/node-introspect which handles function introspection (returning function abstract parameter information). But the second part is missing - mapping map-call into positional-call.
Please tell me, whether such thing exists.
edit: if I didn't make myself clear: I don't want to modify the original positional-argument function. I get such functions from an external provider which may update his code. I'd rather prefer to have a wrapper that could call the original function beneath, and provide a map-argument API outside.
Assuming you have access to introspect
from node-introspect
(which takes a function and returns an ordered list of arguments names), you can simply do:
function objArgsify(fn) {
var argNames = introspect(fn);
return function(obj) {
return fn.apply(this,
argNames.map(function(a) { return obj[a]; });
}
}
Call it by:
var generateEmailWithObjArgs = objArgsify(generateEmail);
generateEmailWithObjArgs({
"firstName":"John",
"lastname": "Smith",
"provider": "gmail.com"
});
This accepts a function, reads its argument names, and then returns a wrapper function that accepts an object and uses the positional argument names to pull properties from the object-argument in the correct order.
This function uses the call-time object-argument as a map to transform the array ["firstName", "lastname", "provider"]
into the array ["John", "Smith", "gmail.com"]
. That array is then used with apply
to invoke the postional-argument function.
Without using any external libraries,
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
function getParamNames(func) {
var fnStr = func.toString().replace(STRIP_COMMENTS, '');
var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if(result === null)
result = [];
return result;
}
function call(method, object) {
var params = getParamNames(method);
var arrParams = [];
for (var i = 0; i < params.length; i++) {
arrParams.push(object[params[i]]);
}
return method.apply(arrParams);
}
Just call it with call(generateEmail, generateEmailObject)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With