Inspired by the previous thread on Optional Named Parameters...
function stringify(data, ?{replacer, indent} ) {...}
// These are the same:
stringify(myData, undefined, 2)
stringify(myData, {indent: 2})
stringify(myData, undefined, {indent:2}) // (though this one is silly))
stringify(myData, {indent: 2, replacer:undefined}) // as is this
// These aren't
stringify(myData,x=>x+1,{indent:2,replacer:undefined}) // The positional value dominates
stringify(myData,{replacer:undefined},{indent:2}) // The non-final argument is not destructured
When a function declaration uses the ?{}
notation and is called with the last argument being an object, that object is deconstructed over the arguments that have not been assigned positionally.
Using this with arguments that will ever be objects is discouraged, though you can still pass them in named mode, so a function that takes objects as those arguments on rare occasions might still use this feature. In order to avoid bugs in this scenario, we might raise an exception on unused keys in the passed object.
This has all the usual advantages of optionally named arguments, allowing programmers to consider clarity and compactness in the context of the code they're actually writing. This is familiar to us from python.
But by being explicit, it means that a function's author gets to decide whether name, ordering or both of arguments is part of the signature, so they won't break users by accident. Also, we're using standard destructuring that is already well understood.
You may have recognized the stringify
function from my example. I got it from the JSON
library. If it were being designed today, it would probably take the latter two arguments as named, but it predates object destructuring and changing the api would break far too much code. But shifting it to optional named arguments in this way allows old code to keep working and new code to use clearer calling.
There's a lot of functions in the JS standard library that would benefit from a non-breaking conversion to named arguments.