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
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".
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.
Here our benefit is that we created an independent function with a readable name (`double`, `triple`). We can use it and don't write the first argument of every time, cause it's fixed with `bind`.
In other cases, partial application is useful when we have a very generic function, and want a less universal variant of it for convenience.
62
+
在其他的场景中,当我们有一个非常通用的函数,并且想要方便地获取它的特定变体,偏函数也是非常有用。
63
63
64
-
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.
64
+
举个例子,我们拥有函数 `send(from, to, text)`。然后,在 `user`对象中,我们想要使用它的偏函数变体:`sendTo(to, text)`,该函数表明发送自一个当前的用户。
65
65
66
-
## Going partial without context
66
+
## 无上下文使用偏函数
67
67
68
-
What if we'd like to fix some arguments, but not bind `this`?
68
+
如果我们想要输入一些参数,但是不想绑定 `this`,该怎么做?
69
69
70
-
The native `bind`does not allow that. We can't just omit the context and jump to arguments.
70
+
原生的 `bind`不允许这样。我们不能忽略上下文,直接跳到参数。
71
71
72
-
Fortunately, a `partial` function for binding only arguments can be easily implemented.
72
+
幸运的是,一个只绑定参数的 `偏函数` 很容易实现。
73
73
74
-
Like this:
74
+
就像这样:
75
75
76
76
```js run
77
77
*!*
@@ -82,38 +82,38 @@ function partial(func, ...argsBound) {
82
82
}
83
83
*/!*
84
84
85
-
//Usage:
85
+
//用法:
86
86
let user = {
87
87
firstName:"John",
88
88
say(time, phrase) {
89
89
alert(`[${time}] ${this.firstName}: ${phrase}!`);
90
90
}
91
91
};
92
92
93
-
//add a partial method that says something now by fixing the first argument
Sometimes people mix up partial function application mentioned above with another thing named "currying". That's another interesting technique of working with functions that we just have to mention here.
More advanced implementations of currying like [_.curry](https://lodash.com/docs#curry)from lodash library do something more sophisticated. They return a wrapper that allows a function to be called normally when all arguments are supplied *or* returns a partial otherwise.
//if args.length == f.length (as many arguments as f has),
151
-
// then pass the call to f
152
-
//otherwise return a partial function that fixes args as first arguments
150
+
//如果 args.length == f.length(args 和 f 的参数数量相同)
151
+
//那么调用 f
152
+
//否则的话返回一个偏函数,将 args 作为第一个参数
153
153
};
154
154
}
155
155
```
156
156
157
-
## Currying? What for?
157
+
## 柯里化?目的是什么?
158
158
159
-
Advanced currying allows both to keep the function callable normally and to get partials easily. To understand the benefits we definitely need a worthy real-life example.
159
+
高级的柯里化同时允许函数正常调用和获取偏函数。为了理解这样的好处,我们确实需要一个好的现实例子。
160
160
161
-
For instance, we have the logging function `log(date, importance, message)`that formats and outputs the information. In real projects such functions also have many other useful features like: sending it over the network or filtering:
Let's get a convenience function for today's logs:
187
+
让我们来创建一个获取今天的日志的简易函数:
188
188
189
189
```js
190
-
// todayLog will be the partial of log with fixed first argument
190
+
// todayLog 会是一个首个参数确定的偏函数
191
191
let todayLog =log(newDate());
192
192
193
-
//use it
193
+
//使用它
194
194
todayLog("INFO", "message"); // [HH:mm] INFO message
195
195
```
196
196
197
-
And now a convenience function for today's debug messages:
197
+
接下来是提供今天的调试信息的简便函数:
198
198
199
199
```js
200
200
let todayDebug =todayLog("DEBUG");
201
201
202
202
todayDebug("message"); // [HH:mm] DEBUG message
203
203
```
204
204
205
-
So:
206
-
1.We didn't lose anything after currying: `log`is still callable normally.
207
-
2.We were able to generate partial functions that are convenient in many cases.
205
+
那么:
206
+
1.柯里化之后我们没有丢失任何东西:`log`依然可以被正常调用。
207
+
2.在很多情况下我们可以很方便生成偏函数。
208
208
209
-
## Advanced curry implementation
209
+
## 高级柯里化实现
210
210
211
-
In case you're interested, here's the "advanced" curry implementation that we could use above.
211
+
由于你可能感兴趣,下面是我们可以使用的「高级」柯里化实现
212
212
213
213
```js run
214
214
functioncurry(func) {
@@ -231,22 +231,22 @@ function sum(a, b, c) {
231
231
232
232
let curriedSum =curry(sum);
233
233
234
-
//still callable normally
234
+
//依然可以被正常调用
235
235
alert( curriedSum(1, 2, 3) ); // 6
236
236
237
-
//get the partial with curried(1) and call it with 2 other arguments
237
+
//得到 curried(1) 的偏函数,然后用另外两个参数调用它
238
238
alert( curriedSum(1)(2,3) ); // 6
239
239
240
-
//full curried form
240
+
//完全柯里化形式
241
241
alert( curriedSum(1)(2)(3) ); // 6
242
242
```
243
243
244
-
The new `curry` may look complicated, but it's actually pretty easy to understand.
244
+
新的「柯里函数」看上去有点复杂,但是它很容易理解。
245
245
246
-
The result of `curry(func)`is the wrapper `curried`that looks like this:
246
+
`curry(func)`的结果是 `curried`函数的封装,结果如下:
247
247
248
248
```js
249
-
// func is the function to transform
249
+
// func 是被转化的函数
250
250
functioncurried(...args) {
251
251
if (args.length>=func.length) { // (1)
252
252
returnfunc.apply(this, args);
@@ -258,39 +258,39 @@ function curried(...args) {
258
258
};
259
259
```
260
260
261
-
When we run it, there are two branches:
261
+
当我们运行它的时候,有两种结果:
262
262
263
-
1.Call now: if passed `args`count is the same as the original function has in its definition (`func.length`) or longer, then just pass the call to it.
264
-
2.Get a partial: otherwise, `func` is not called yet. Instead, another wrapper `pass` is returned, that will re-apply `curried`providing previous arguments together with the new ones. Then on a new call, again, we'll get either a new partial (if not enough arguments) or, finally, the result.
1.The first call `curried(1)`remembers`1`in its Lexical Environment, and returns a wrapper `pass`.
271
-
2.The wrapper `pass`is called with `(2)`: it takes previous args (`1`), concatenates them with what it got `(2)`and calls `curried(1, 2)` with them together.
As the argument count is still less than 3, `curry`returns`pass`.
274
-
3.The wrapper `pass`is called again with `(3)`, for the next call `pass(3)`takes previous args (`1`, `2`) and adds `3`to them, making the call `curried(1, 2, 3)`-- there are `3`arguments at last, they are given to the original function.
-When we fix some arguments of an existing function, the resulting (less universal) function is called *a partial*. We can use `bind`to get a partial, but there are other ways also.
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.
-*Currying* is a transform that makes `f(a,b,c)`callable as `f(a)(b)(c)`. JavaScript implementations usually both keep the function callable normally and return the partial if arguments count is not enough.
Currying is great when we want easy partials. As we've seen in the logging example: the universal function `log(date, importance, message)`after currying gives us partials when called with one argument like `log(date)`or two arguments `log(date, importance)`.
0 commit comments