How can I have a function accept either named arguments (foo({a: 'hello', b: 'it is me'})
) or positional arguments (foo('hello', 'it is me')
)?
I understand that named arguments can be simulated by passing an object to the function:
function foo(options) {
options = options || {};
var a = options.a || 'peanut'; // whatever default value
var b = options.b || 'butter'; // whatever default value
console.log(a, b);
}
// ES6 allows automatic destructuring
function foo({a = 'peanut', b = 'butter'} = {}) {
console.log(a, b);
}
But that does not allow me to accept positional arguments to be passed.
I would like to use ES6 but anything from ES5 would be ok too.
The important takeaway here is that the name of the argument doesn't have any significance. The only thing that matters is the order in which the arguments are passed. This familiar approach is called positional arguments.
As we can see what we call named arguments is nothing more than a destructuring of the keys of an object that in this case will act as "arguments" of the function.
Let's start by creating a function called add that can accept 2 arguments and that returns their sum. We can use Node. js to run the code node add_2_numbers.
Functions with a mix of positional arguments and keyword arguments. It is common to have functions with both positional arguments (with and without default value )and key word arguments (with and without default value) with the help of / and * symbols (from Python 3.8 ).
First of all, I really would recommend to stick with one approach. As you said, use either "named"
function foo({a = 'peanut', b = 'butter'} = {}) {
console.log(a, b);
}
or positional arguments:
function foo(a = 'peanut', b = 'butter') {
console.log(a, b);
}
Choose the one that fits your function better, do not mix both.
If you really need both for some reason, standard overloading techniques are available to you. It'll only work properly if your first positional argument is not an object. I would propose one of the following idioms:
function foo(a, b) { // positional is normal case
if (arguments.length == 1 && typeof arguments[0] == "object")
{a, b} = arguments[0];
console.log(a, b);
}
function foo({a, b}) { // named is normal case
if (arguments.length > 1 || typeof arguments[0] != "object")
[a, b] = arguments;
console.log(a, b);
}
and if you need default values, it gets ugly either way:
function foo(a, b) {
var opts = (arguments.length == 1 && typeof arguments[0] == "object")
? arguments[0]
: {a, b};
({a = 'peanut', b = 'butter'} = opts);
console.log(a, b);
}
I suppose something like this would work:
function foo(...options){
if (typeof options[0] === 'object'){
console.log('expect object', options[0]);
}else{
console.log('expect array', options);
}
}
foo('peanut', 'butter');
foo({a:'peanut', b:'butter'});
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