You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/10-bind/article.md
+117-1Lines changed: 117 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -196,8 +196,124 @@ for (let key in user) {
196
196
JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(obj)](http://lodash.com/docs#bindAll) in lodash.
197
197
````
198
198
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
+
199
311
## Summary
200
312
201
313
Method `func.bind(context, ...args)` returns a "bound variant" of function `func` that fixes the context `this` and first arguments if given.
202
314
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