In Python
I'm sure it's been blogged about a buncha times before but, I couldn't find it, and I had to search too hard to find an example of this. Basically, what I'm trying to do is what Python does in this case, but in JavaScript:
def do_something(arg="notset", **kwargs):
print(f"arg='{arg.upper()}'")
do_something(arg="peter")
do_something(something="else")
do_something()
In Python, the output of all this is:
arg='PETER'
arg='NOTSET'
arg='NOTSET'
It could also have been implemented in a more verbose way:
def do_something(**kwargs):
arg = kwargs.get("arg", "notset")
print(f"arg='{arg.upper()}'")
This more verbose format has the disadvantage that you can't quickly skim it and see and what the default is. That thing (arg = kwargs.get("arg", "notset")
) might happen far away deeper in the function, making it hard work to spot the default.
In JavaScript
Here's the equivalent in JavaScript (ES6?):
function doSomething({ arg = "notset", ...kwargs } = {}) {
return `arg='${arg.toUpperCase()}'`;
}
console.log(doSomething({ arg: "peter" }));
console.log(doSomething({ something: "else" }));
console.log(doSomething());
Same output as in Python:
arg='PETER'
arg='NOTSET'
arg='NOTSET'
Notes
I'm still not convinced I like this syntax. It feels a bit too "hip" and too one-liner'y. But it's also pretty useful.
Mind you, the examples here are contrived because they're so short in terms of the number of arguments used in the function.
A more realistic thing like be a function that lists, upfront, all the possible parameters and for some of them, it wants to point out some defaults. E.g.
function processFolder({
source,
destination = "/tmp",
quiet = false,
verbose = false
} = {}) {
console.log({ source, destination, quiet, verbose });
}
console.log(processFolder({ source: "/user", quiet: true }));
One could maybe argue that arguments that don't have a default are expected to always be supplied so they can be regular arguments like:
function processFolder(source, {
destination = "/tmp",
quiet = false,
verbose = false
} = {}) {
console.log({ source, destination, quiet, verbose });
}
console.log(processFolder("/user", { quiet: true }));
But, I quite like keeping all arguments in an object. It makes it easier to write wrapper functions and I find this:
setProfile(
"My biography here",
false,
193.5,
230,
["anders", "bengt"],
"South Carolina"
);
...harder to read than...
setProfile({
bio: "My biography here",
dead: false,
height: 193.5,
weight: 230,
middlenames: ["anders", "bengt"],
state: "South Carolina"
});