I have been using parameter destructuring when making function calls and I love it. I use the destructuring where I used to call functions with an options object. I find the new way much simpler, safer and easier to read than options object.
The options object
Any function with more than 2 arguments can benefit from using an options object pattern to pass its arguments.
1 | // BAD |
When passing an options object, I no longer need to worry about or remember the function's signature; or how to pass the default values for parameters I want to skip.
Parameter destructuring
The ES6 allows me to construct and destruct an object on the fly. For example, I can still call the function with an object, but inside the function grab only the needed properties.
1 | function doSomething({a, b}) { |
The destructuring has several benefits in my opinion.
The input values are immutable
Nothing (except deep freezing) prevents a function from modifying properties inside a passed
object. This affects any code that passes around options
object.
1 | function doSomething(options) { |
Destructuring on the other hand severely limits what the function can do, because the inputs are passed by value. Even better, the function does NOT have access to the inputs NOT listed in its signature.
1 | function doSomething({a, b}) { |
The later approach makes the code easier to read and understand.
Destructuring makes it easy to use consistent variable names
When passing individual variables or options object, it is easy to make up variable names. But if we apply destructuring when calling the function, we have to use the same variable names at the caller as inside the function (I am ignoring parameter renaming feature, since it just adds more noise to the code in my opinion).
1 | // BAD |
Note that we used variables apps
and ors
in the caller, and had to use the expected
property names only when calling the compare
function.
We could not even easily inspect the signature
of compare
because options
parameter is opaque.
In contrast, if we create an object from variables, we need to have the variables match names with the declared parameter names in the function signature, keeping the whole thing consistent.
1 | // GOOD |
The above syntax is short and consistent. I like the fact that the caller is "forced" to use the parameter names from the function's public "API" (the function's signature).
Partial application
One downside of the options and destructuring technique is that one cannot partially apply parameter values easily.
1 | // "normal" function |
If we know the value of "apples" or "oranges" already, how do we create a new function that just waits for the remaining value? Luckily, a function to do this is simple to write, and the one I wrote for working with options object applies perfectly to destructured calls. obind stands for "options bind" and can "pre-fill" properties inside a given object.
1 | const obind = require('obind') |
Nice!