curry
就是咖喱同样美好的工具性的拌料让咱们的函数更加的易用、低耦合性。html
curry
的概念很简单:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。 你能够一次性地调用 curry
函数,也能够每次只传一个参数分屡次调用。git
var add = function(x) {
return function(y) {
return x + y;
};
};
var increment = add(1);
var addTen = add(10);
increment(2);
// 3
addTen(2);
// 12
复制代码
在这个多彩的世界,有些事物对与咱们来讲并非非必须的,就像咱们早已习惯存在可是又非必须的东西:互联网,移动手机,微波炉,电梯等等。当他们不存在的时候咱们也能正常的快乐的生存下去,可是一旦拥有了之后他们的存在就变得不可或缺。就像咱们的 curry 工具同样。github
var curry = require('lodash').curry;
var match = curry(function(what, str) {
return str.match(what);
});
var replace = curry(function(what, replacement, str) {
return str.replace(what, replacement);
});
var filter = curry(function(f, ary) {
return ary.filter(f);
});
var map = curry(function(f, ary) {
return ary.map(f);
});
复制代码
我在上面的代码中遵循的是一种简单,同时也很是重要的模式。即策略性地把要操做的数据(String, Array)放到最后一个参数里。到使用它们的时候你就明白这样作的缘由是什么了。npm
// 匹配空格
match(/\s+/g, "hello world");
// [ ' ' ]
match(/\s+/g)("hello world");
// [ ' ' ]
// 引出一个 hasSpace 的函数变量,暂存用
var hasSpaces = match(/\s+/g);
// function(x) { return x.match(/\s+/g) }
// 使用这个 hasSpace 去作一些相关的处理
hasSpaces("hello world");
// [ ' ' ]
hasSpaces("spaceless");
// null
// 如今咱们知道了它的返回值,咱们能够经过其余函数作进一步的处理。好比筛选出一个有空格的数组值
filter(hasSpaces, ["tori_spelling", "tori amos"]);
// ["tori amos"]
// 保存这个 findSpace 的函数变量
var findSpaces = filter(hasSpaces);
// function(xs) { return xs.filter(function(x) { return x.match(/\s+/g) }) }
// 轻松的使用吧
findSpaces(["tori_spelling", "tori amos"]);
// ["tori amos"]
var noVowels = replace(/[aeiou]/ig);
// function(replacement, x) { return x.replace(/[aeiou]/ig, replacement) }
var censored = noVowels("*");
// function(x) { return x.replace(/[aeiou]/ig, "*") }
censored("Chocolate Rain");
// 'Ch*c*l*t* R**n'
复制代码
咱们为甚要这么多繁琐的步骤,而不是一步到位? 编程
这里代表的是一种“预加载”函数的能力,经过传递一到两个参数调用函数,就能获得一个记住了这些参数的新函数。分解的使用的函数,让每一个函数更具备必定的独立性,使用导出的时候,作到纯净无污染的传递。数组
curry
的用处很是普遍,就像在 hasSpaces
、findSpaces
和 censored
看到的那样,只需传给函数一些参数,就能获得一个新函数。app
map
包裹一下咱们的函数var getChildren = function(x) {
return x.childNodes;
};
var allTheChildren = map(getChildren);
复制代码
只传给函数一部分参数这样的操做一般被称为局部调用(partial application),由于只须要内联调用可以大量减小样板文件代码(boilerplate code)。less
当咱们谈论纯函数的时候,咱们说它们接受一个输入返回一个输出。curry 函数所作的正是这样:每传递一个参数调用函数,就返回一个新函数处理剩余的参数。这就是一个输入对应一个输出啊。ide
npm install ramda
var _ = require('ramda');
// 练习 1(局部调用的使用)
//==============
// 经过局部调用(partial apply)移除全部参数
var words = function(str) {
return split(' ', str);
};
// 练习 1a(组合使用函数)
//==============
// 使用 `map` 建立一个新的 `words` 函数,使之可以操做字符串数组
var sentences = undefined;
// 练习 2
//==============
// 经过局部调用(partial apply)移除全部参数
var filterQs = function(xs) {
return filter(function(x){ return match(/q/i, x); }, xs);
};
// 练习 3(柯里化~)
//==============
// 使用帮助函数 `_keepHighest` 重构 `max` 使之成为 curry 函数
// 无须改动:
var _keepHighest = function(x,y){ return x >= y ? x : y; };
// 重构这段代码:
var max = function(xs) {
return reduce(function(acc, x){
return _keepHighest(acc, x);
}, -Infinity, xs);
};
// use curry 1:
// ============
// 包裹数组的 `slice` 函数使之成为 curry 函数
// //[1,2,3].slice(0, 2)
var slice = undefined;
// use curry 2:
// ============
// 借助 `slice` 定义一个 `take` curry 函数,该函数调用后能够取出字符串的前 n 个字符。
var take = undefined;
复制代码
这是上面的答案 Q&A,先别急着看答案,让咱们先思考一下函数式编程
经过简单地传递几个参数,就能动态建立实用的新函数;并且还能带来一个额外好处,那就是保留了数学的函数定义,尽管参数不止一个。
下篇连接 了解 JavaScript 函数式编程 - 代码组合的优点