近来在进修javascript函数式编程,对个中赫赫有名的curry非常感兴趣,curry函数能够接收一个函数,我们临时称之为原始函数,返回的也是一个函数,柯里化函数,这个返回的柯里化函数功用非常壮大,他在实行的过程当中,不停的返回一个储存了传入参数的函数,直到触发了原始函数实行的前提。这么说比较归纳综合,那末就举个例子来申明一下:
原始函数:
var add = (x, y) => x + y
柯里化函数:
var curryAdd = curry(add)
这个add须要两个参数,然则我们的curryAdd实行能够传入更少的参数,当传入的参数少于add须要的参数的时刻,add函数并不会实行,curryAdd就会将这个参数记下来,而且返回别的一个函数,这个函数能够继承实行传入参数,我们会有一个变量特地纪录传入参数的状况,假如传入参数的总数即是add须要参数的总数,我们就激活了原始参数实行,就会返回我们想要的效果。
// 此时只传入了一个参数 依据推断返回的是一个函数
var add2 = curryAdd(2)
// add2 = function(...) {}
// 此时累计传入了两个参数 即是了add须要参数的总和 所以返回的是一个效果
// 相当于实行了add(2)(3)
var result = add2(3)
// result = 5
照样很不错的是吧,好吧,我们的目标是为了写出这个奇异curry函数,而且还要一行写出来,不要焦急,先剖析一下怎样去写,然后再一步步的优化。
那依据上面的形貌,我们看一下curry函数须要什么,起首须要一个变量,用来存下来原始函数的参数个数,我们晓得function有一个属性为length,对就是它,我们用limit存下来
var curry = function(fn) {
var limit = fn.length
...
}
curry函数要返回一个函数, 这个函数是要实行的,那末题目就是,我们要推断这个函数的实行是不是激活了原始函数的实行,题目就出如今传入的参数上面。返回函数照样效果?这的确是一个题目,
我们先写返回效果的状况,当传入的参数即是原始函数须要的参数时,我们实行原始函数fn
var curry = function(fn) {
var limit = fn.length
return function (...args) {
if (args.length >= limit) {
return fn.apply(null, args)
}
}
}
不然呢 我们就要返回一个储存了参数的函数,这里有两点,一是参数的传入汗青我们要纪录下来,二是这个返回的函数须要做些什么
var curry = function(fn) {
var limit = fn.length
return function (...args) {
if (args.length >= limit) {
return fn.apply(null, args)
} else {
return function(...args2) {
}
}
}
}
看出来了吧 我们只须要把返回函数实行的参数累加起来就达到了纪录参数传入状况的目标,因而我们想到了concat 对 args.concat(args2), 顺次类推,我们返回的函数要做的就是反复做上面的事变,也就是参数为args的函数要做的事变,所以他须要一个名字,不然我们没法实行,我们叫它judgeCurry
所以正如我们所说的,要么返回一个函数,要么实行原始函数。
var curry = function(fn) {
var limit = fn.length
return function judgeCurry (...args) {
if (args.length >= limit) {
return fn.apply(null, args)
} else {
return function(...args2) {
return judgeCurry.apply(null, args.concat(args2))
}
}
}
}
我们终究写完了这个奇异的curry函数,它真的很壮大,合营compose,那真是一个字,爽。
我们的目标照样一行把上面谁人函数写出来,一行写?怎样写?对了,用ES6啊,因而一番折腾
var currySingle = fn => judgeCurry = (...args) => args.length >= fn.length ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2))
好,我们看一下哪有题目,对了,就是我们为了不必limit参数,用了就得赋值,赋值就不能一行搞定了,就会变成如许
var currySingle = fn => {
var limit = fn.length
var judgeCurry = null
return judgeCurry = (...args) => args.length >= limit ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2))
}
须要推断参数的时刻不停的对fn.length求值,然则fn.length的值是肯定的,我们不想每次都求值,但又不想用limit怎样办,有什么方法呢?你肯定想到了,马上实行函数!!
var currySingle = fn => ((limit) => judgeCurry = (...args) => args.length >= limit ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2)))(fn.length)
不能不叹息javascript的奇异,终究,我们就一即将这个奇异的curry写出来了。。。