共计 2518 个字符,预计需要花费 7 分钟才能阅读完成。
介绍
柯理化是一种对于函数的高阶技术。
柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。
柯里化不会调用函数。它只是对函数进行转换。
一个最简略的例子
// 本来的 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
为什么要柯理化
柯理化的应用必定不是为了装逼, 或者说不仅仅为了装逼。
柯理化能够提早执行,达到参数复用的目标。(集体了解动静函数和惰性函数和柯理化没啥关系)
原先是 sum(1,2)立刻执行,当初能够先 fn=sum(1) 而后再 fn(2) 这个就对于函数的执行可控了
第一次传参并不执行,咱们先潜伏它一波。
前面函数执行的时候复用的咱们第一次传的参,这个就叫提早执行,参数复用。这样能够大幅度简化咱们的代码。
一个能投入使用的柯理化函数长啥样
尽管咱们能够依据柯理化的思维,写出咱们想要的函数,比方之前的curry_sum
然而咱们最好能写个更通用的柯理化函数,它承受一个 fn, 返回一个包装后的函数 curry_fn,实现咱们所须要的参数复用和提早执行性能。
这里参考 Lodash 咱们看一个 curry 函数长啥样
/**
* 参数
* func: 用来柯里化(curry)的函数。* [arity=func.length] : 须要提供给 func 的参数数量。*
* 返回
* (Function): 返回新的柯里化(curry)函数。*/
function curry(func, [arity=func.length]){}
咱们给出它的测试用例
// 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)
})
实现
咱们在 index.js 外面实现一个 curry 函数
实现的时候须要留神几个关键点
- 利用闭包保留参数
- fn 真正执行是传的参数达到 fn 承受的参数个数时
- 这里要思考 this 的指向, 咱们用 apply 函数,同时不能在这应用箭头函数,箭头函数外面 apply 有效,而且是指向定义时的 this,node 外面也就是空对象
- 递归的一个应用
//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}
咱们跑一下测试用例,证实函数没有问题。
柯理化实用例子
看两个柯理化的例子,加深一下了解
封装申请
比方 api 长这样 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)
简化解决数据
拿到后盾的数据 常常要解决
比方原始数据 const data = [{name: ‘kevin’}, {name: ‘daisy’}]
咱们须要解决成 [‘kevin’,’daisy’]
每次在这都调用 Map 办法实际上代码很臃肿
var _data = data.map(function (item) {return item.name;})
咱们其实能够这么写, 这也是利用了柯理化
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 中的 === 改为 >== 大家能够好好想一想起因,
*/
总结
柯理化其实挺罕用的,不肯定非要用 curry 函数,了解它的思维咱们就能写出很柔美很高效的代码。
总归就是闭包的一种利用。
参考文章
柯理化
JavaScript 专题之函数柯里化
lodash_curry
深刻高阶函数利用之柯里化
https://segmentfault.com/a/1190000018180159