Problem
In some circumstances, I find Cnamed #’s parameters feature very beneficial.
calculateBMI(70, height: 175);
If I want to do something in JavaScript, what can I do?
This is what I don’t want:
myFunction({ param1: 70, param2: 175 });
function myFunction(params){
// Check if params is an object
// Check if the parameters I need are non-null
// Blah blah
}
I’ve already tried that approach. Is there any other option?
I’m fine with utilizing any library for this.
Asked by Robin Maben
Solution #1
ES2015 and later
To emulate named parameters in ES2015, parameter destructuring can be utilized. It would require the caller to give an object, but if you also use default arguments, you can eliminate all of the tests inside the function:
myFunction({ param1 : 70, param2 : 175});
function myFunction({param1, param2}={}){
// ...function body...
}
// Or with defaults,
function myFunc({
name = 'Default user',
age = 'N/A'
}={}) {
// ...function body...
}
ES5
There is a way to come close to what you want, but it is based on the output of Function.prototype.toString [ES5], which is implementation dependent to some degree, so it might not be cross-browser compatible.
The idea is to parse the parameter names from the string representation of the function so that you can associate the properties of an object with the corresponding parameter.
The following is an example of a function call:
func(a, b, {someArg: ..., someOtherArg: ...});
where a and b are positional arguments, and the final argument is a named argument object.
For example:
var parameterfy = (function() {
var pattern = /function[^(]*\(([^)]*)\)/;
return function(func) {
// fails horribly for parameterless functions ;)
var args = func.toString().match(pattern)[1].split(/,\s*/);
return function() {
var named_params = arguments[arguments.length - 1];
if (typeof named_params === 'object') {
var params = [].slice.call(arguments, 0, -1);
if (params.length < args.length) {
for (var i = params.length, l = args.length; i < l; i++) {
params.push(named_params[args[i]]);
}
return func.apply(this, params);
}
}
return func.apply(null, arguments);
};
};
}());
Which of the following would you use as:
var foo = parameterfy(function(a, b, c) {
console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);
});
foo(1, 2, 3); // a is 1 | b is 2 | c is 3
foo(1, {b:2, c:3}); // a is 1 | b is 2 | c is 3
foo(1, {c:3}); // a is 1 | b is undefined | c is 3
foo({a: 1, c:3}); // a is 1 | b is undefined | c is 3
DEMO
There are some disadvantages to this strategy (warning! ):
Instead of building the wrapper with a function, you might use a function that accepts a function and multiple values as arguments, such as
call(func, a, b, {posArg: ... });
or even increase the functionality create a prototype so that you can:
foo.execute(a, b, {posArg: ...});
Answered by Felix Kling
Solution #2
No – the object approach is JavaScript’s answer to this. There is no problem with this provided your function expects an object rather than separate params.
Answered by Mitya
Solution #3
Many people recommend simply using the “Pass an object” approach to get named parameters.
/**
* My Function
*
* @param {Object} arg1 Named arguments
*/
function myFunc(arg1) { }
myFunc({ param1 : 70, param2 : 175});
And that’s fantastic, except…. in most IDEs, a lot of us devs rely on type / argument clues within our IDE. PHP Storm is what I use (Along with other JetBrains IDEs like PyCharm for python and AppCode for Objective C)
The major issue with using the “Pass an object” trick is that the IDE only provides you a single type suggestion when you call the function… How will we know which parameters and types to include in the arg1 object?
So, the “Pass an item” approach doesn’t seem to work for me… It really gives me more hassles because I have to look at each function’s docblock to figure out what parameters it wants…. Sure, it’s fantastic for maintaining old code; but, it’s terrible for writing new code.
So, here is the method I employ…. Now, there may be some problems with it, and some devs may tell me I’m doing it incorrectly, but I keep an open mind about these things… I’m always willing to consider alternative approaches to completing a task… So, if there is a problem with this strategy, please share your thoughts.
/**
* My Function
*
* @param {string} arg1 Argument 1
* @param {string} arg2 Argument 2
*/
function myFunc(arg1, arg2) { }
var arg1, arg2;
myFunc(arg1='Param1', arg2='Param2');
This gives me the best of both worlds: new code is simple to create because my IDE provides all of the necessary argument indications… And, later on, when maintaining code, I can see not only the value supplied to the function, but also the name of the argument at a look. Declaring your parameter names as local variables to avoid polluting the global namespace is the only burden I perceive. Sure, it’s a little more typing, but it’s nothing compared to the time spent looking up docblocks while building new code or maintaining current code.
Answered by Ray Perea
Solution #4
Rather than merely calling each parameter, if you want to make it clear what it is,
someFunction(70, 115);
Why don’t you try this?
var width = 70, height = 115;
someFunction(width, height);
Although it adds an extra line of code, it improves readability.
Answered by dav_i
Solution #5
Another option is to use the attributes of an appropriate object, such as these:
function plus(a,b) { return a+b; };
Plus = { a: function(x) { return { b: function(y) { return plus(x,y) }}},
b: function(y) { return { a: function(x) { return plus(x,y) }}}};
sum = Plus.a(3).b(5);
Of course, it is fairly meaningless in this made-up case. However, in circumstances where the function appears to be
do_something(some_connection_handle, some_context_parameter, some_value)
It could be more beneficial. It might also be used with the “parameterfy” approach to make a generic object out of an existing function. That is, it would produce a member for each parameter that may evaluate to a partially evaluated version of the function.
This concept is, of course, linked to Schönfinkeling, also known as Currying.
Answered by Udo Klein
Post is based on https://stackoverflow.com/questions/11796093/is-there-a-way-to-provide-named-parameters-in-a-function-call-in-javascript