Skip to content

Commit 25a77d3

Browse files
committed
currying
1 parent 799d373 commit 25a77d3

File tree

7 files changed

+308
-307
lines changed

7 files changed

+308
-307
lines changed

1-js/06-advanced-functions/10-bind/article.md

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,124 @@ for (let key in user) {
196196
JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(obj)](http://lodash.com/docs#bindAll) in lodash.
197197
````
198198
199+
## Partial functions
200+
201+
Until now we have only been talking about binding `this`. Let's take it a step further.
202+
203+
We can bind not only `this`, but also arguments. That's rarely done, but sometimes can be handy.
204+
205+
The full syntax of `bind`:
206+
207+
```js
208+
let bound = func.bind(context, [arg1], [arg2], ...);
209+
```
210+
211+
It allows to bind context as `this` and starting arguments of the function.
212+
213+
For instance, we have a multiplication function `mul(a, b)`:
214+
215+
```js
216+
function mul(a, b) {
217+
return a * b;
218+
}
219+
```
220+
221+
Let's use `bind` to create a function `double` on its base:
222+
223+
```js run
224+
function mul(a, b) {
225+
return a * b;
226+
}
227+
228+
*!*
229+
let double = mul.bind(null, 2);
230+
*/!*
231+
232+
alert( double(3) ); // = mul(2, 3) = 6
233+
alert( double(4) ); // = mul(2, 4) = 8
234+
alert( double(5) ); // = mul(2, 5) = 10
235+
```
236+
237+
The call to `mul.bind(null, 2)` creates a new function `double` that passes calls to `mul`, fixing `null` as the context and `2` as the first argument. Further arguments are passed "as is".
238+
239+
That's called [partial function application](https://en.wikipedia.org/wiki/Partial_application) -- we create a new function by fixing some parameters of the existing one.
240+
241+
Please note that here we actually don't use `this` here. But `bind` requires it, so we must put in something like `null`.
242+
243+
The function `triple` in the code below triples the value:
244+
245+
```js run
246+
function mul(a, b) {
247+
return a * b;
248+
}
249+
250+
*!*
251+
let triple = mul.bind(null, 3);
252+
*/!*
253+
254+
alert( triple(3) ); // = mul(3, 3) = 9
255+
alert( triple(4) ); // = mul(3, 4) = 12
256+
alert( triple(5) ); // = mul(3, 5) = 15
257+
```
258+
259+
Why do we usually make a partial function?
260+
261+
The benefit is that we can create an independent function with a readable name (`double`, `triple`). We can use it and not provide first argument of every time as it's fixed with `bind`.
262+
263+
In other cases, partial application is useful when we have a very generic function and want a less universal variant of it for convenience.
264+
265+
For instance, we have a function `send(from, to, text)`. Then, inside a `user` object we may want to use a partial variant of it: `sendTo(to, text)` that sends from the current user.
266+
267+
## Going partial without context
268+
269+
What if we'd like to fix some arguments, but not the context `this`? For example, for an object method.
270+
271+
The native `bind` does not allow that. We can't just omit the context and jump to arguments.
272+
273+
Fortunately, a helper function `partial` for binding only arguments can be easily implemented.
274+
275+
Like this:
276+
277+
```js run
278+
*!*
279+
function partial(func, ...argsBound) {
280+
return function(...args) { // (*)
281+
return func.call(this, ...argsBound, ...args);
282+
}
283+
}
284+
*/!*
285+
286+
// Usage:
287+
let user = {
288+
firstName: "John",
289+
say(time, phrase) {
290+
alert(`[${time}] ${this.firstName}: ${phrase}!`);
291+
}
292+
};
293+
294+
// add a partial method with fixed time
295+
user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());
296+
297+
user.sayNow("Hello");
298+
// Something like:
299+
// [10:00] John: Hello!
300+
```
301+
302+
The result of `partial(func[, arg1, arg2...])` call is a wrapper `(*)` that calls `func` with:
303+
- Same `this` as it gets (for `user.sayNow` call it's `user`)
304+
- Then gives it `...argsBound` -- arguments from the `partial` call (`"10:00"`)
305+
- Then gives it `...args` -- arguments given to the wrapper (`"Hello"`)
306+
307+
So easy to do it with the spread operator, right?
308+
309+
Also there's a ready [_.partial](https://lodash.com/docs#partial) implementation from lodash library.
310+
199311
## Summary
200312
201313
Method `func.bind(context, ...args)` returns a "bound variant" of function `func` that fixes the context `this` and first arguments if given.
202314
203-
Usually we apply `bind` to fix `this` in an object method, so that we can pass it somewhere. For example, to `setTimeout`. There are more reasons to `bind` in the modern development, we'll meet them later.
315+
Usually we apply `bind` to fix `this` for an object method, so that we can pass it somewhere. For example, to `setTimeout`.
316+
317+
When we fix some arguments of an existing function, the resulting (less universal) function is called *partially applied* or *partial*.
318+
319+
Partials are convenient when we don't want to repeat the same argument over and over again. Like if we have a `send(from, to)` function, and `from` should always be the same for our task, we can get a partial and go on with it.

0 commit comments

Comments
 (0)