Introduction
Ke Lihua is a high-level technique about functions.
Currying is a kind of function conversion, which refers to converting a function from callable f(a, b, c) to callable f(a)(b)(c).
Currying does not call functions. It just converts the function.
The simplest example
// 原本的sum函数以及应用
function sum(a, b) {
return a + b;
}
sum(1,2) // 3
// 柯理化后的sum函数以及应用
function curry_sum(a) {
return function(b){
return a+b
}
}
sum(1)(2) // 3
// 或者 fn=sum(1) fn(2) ==>3
Why should Ke Lihua
The use of Ke Lihua is definitely not for pretending, or not just for pretending.
Ke Lihua can delay execution to achieve the purpose of parameter reuse. (Personal understanding of dynamic functions and lazy functions has nothing to do with Ke Lihua)
Originally sum(1,2) was executed immediately, now you can first fn=sum(1) and then fn(2), which can control the execution of the function
The first transfer of parameters is not executed, let's ambush it first.
When the function is executed later, we reuse the parameters we passed for the first time. This is called delayed execution and parameter reuse. This can greatly simplify our code.
What does a function that can be put into use look like?
Although we can write the function we want based on Ke Lihua’s ideas, such as the previous curry_sum
But we'd better write a more general curation function, which accepts a fn and returns a wrapped function curry_fn to complete the parameter reuse and delayed execution functions we need.
Refer to Lodash here, let’s see what a curry function looks like
/**
* 参数
* func: 用来柯里化(curry)的函数。
* [arity=func.length] : 需要提供给 func 的参数数量。
*
* 返回
* (Function): 返回新的柯里化(curry)函数。
*/
function curry(func, [arity=func.length]){
}
We give its test case
// curry.test.js
const{curry} = require('./index')
test('curry',()=>{
const add = (a,b,c)=>{
return a+b+c
}
const sayhi = function(){
return this.name
}
const curry_add = curry(add)
const curry_sayhi = curry(sayhi)
const obj = {name:'fyy'}
expect(curry_sayhi.call(obj)).toBe('fyy')
expect(curry_add(2)(3)(4)).toBe(9)
expect(curry_add(1)(2,3)).toBe(6)
expect(curry_add(1,2)(2)).toBe(5)
expect(curry_add(1,2,1)).toBe(4)
})
achieve
We implement a curry function in index.js
Several key points need to be paid attention to when implementing
- Use closures to save parameters
- The real execution of fn is when the passed parameters reach the number of parameters accepted by fn
- Here we need to consider the direction of this. We use the apply function, and at the same time, we cannot use the arrow function here. Apply is invalid in the arrow function, and it points to the this at the time of definition. The node is an empty object.
- A use of recursion
//index.js
const curry = function(fn){
return function curried(...args){ //这里不能用箭头函数
if(fn.length===args.length){
return fn.apply(this,args)
}else{
return function(...args1){
return curried.apply(this,args.concat(args1))
}
}
}
}
module.exports = {
curry
}
Let's run a test case to prove that the function is ok.
Ke Lihua practical examples
Look at two examples of Ke Lihua to deepen your understanding
Package request
For example, the api looks like this ajax (method, url, params)
// 我们可以在serve.js里封装一个post
const post = url=> data => ajax('post',url,params)
// 在module1api.js里面封装一些地址
import {post} from 'serve.js'
const getList = post('www.xxx.com/api/xxx')
// 在需要调接口的地方,我们只用传递参数就行了,调用方式和地址已经提前穿过了
// 第一处地方
import{getList} from 'module1api.js'
const data = getList(params)
// 第二处地方
import{getList} from 'module1api.js'
const data = getList(params)
// 第N处地方...
import{getList} from 'module1api.js'
const data = getList(params)
Simplify processing data
The data received in the background often needs to be processed
For example, raw data const data = [{name:'kevin'}, {name:'daisy'}]
We need to process into ['kevin','daisy']
Every time I call the Map method here, the code is actually bloated
var _data = data.map(function (item) {
return item.name;
})
In fact, we can write like this, which also makes use of Ke Lihua
const prop = curry(function (key, obj) {
return obj[key]
});
var _data = person.map(val=>prop('name')(val))
// var _data = person.map(prop('name'))
/*
*如果想直接这么调的话,curry需要改一下,
把fn.length===args.length中的===改为>== 大家可以好好想一想原因,
*/
to sum up
Ke Lihua is actually quite commonly used. It is not necessary to use the curry function, and we can write very beautiful and efficient code by understanding its ideas.
It is always an application of closures.
Reference article
Ke Lihua
JavaScript topic function currying
lodash_curry
in-depth application of higher-order functions
https://segmentfault.com/a/1190000018180159
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。