Partial application review
JavaScript Function.prototype.bind
performs both context binding and partial application.
Let us review the partial application: one can bind argument values in the left to right order,
creating a new function.
1 | function add(a, b) { |
We have created a new function add10
from the existing function add
by using the provided bind
method.
Calling add10(3)
is equivalent to calling add(10, 3)
- the single provided value 10
was bound to the first
argument a
. We could even create a function that binds all arguments
1 | var add2to3 = add.bind(null, 2, 3); |
Limitations
In order to bind the function's arguments one has to list the arguments separately. Thus we could
bind the first argument a
in the function add(a, b)
. I often find that any function with more than 2
arguments needs to accept an options object instead of separate arguments. This simplifies the
API, removes the need to remember the arguments order and allows easy argument defaults. For example,
1 | function calc(options) { |
We have implemented a more general API for addition and subtraction reusing the same addition function
1 | console.log(calc({ |
Note that instead of remembering the order of arguments
(is it operand then arguments or is the operand between them?
),
we just pass a single options object.
Now we encounter a problem: we can no longer bind some values to the calc
arguments using the partial application mechanism!
How can we create an adder function for example? We need to be able to fill a property inside the options
object.
1 | var add10 = add.bind(null, 10); |
We need an utility method that could fill some values in the single options object.
obind
I wrote obind that does just that: partial application for options
object.
1 | var obind = require('obind'); |
One can even bind multiple properties at once, or in several steps. For example,
we can make adder10
by binding a
property.
1 | var adder10 = obind(adder, { a: 10 }); |
Note that obind
only does the partial application and not the context bind, thus no need to pass the null
value
as the first argument.
I tried to make obind
behave the same way as its functional inspiration. For example,
even if no arguments are provided, it returns a new function
1 | // Function.prototype.bind always returns new function |
There are just two obind-specific differences
1: One need to provide at least an empty object when using obind
, for example obind(adder, {})
,
otherwise it throws an error. I made this choice to simplify the debugging; if there is nothing or a non plain
JavaScript object, something is wrong.
2: I make a deep clone of the options object to prevent changing the bound values. Otherwise the values inside the first object could be changed later leading to very unexpected behavior.
1 | var a2 = { a: 2 }; |